loading
Generated 2020-10-18T23:38:56-04:00

All Files ( 72.64% covered at 557.81 hits/line )

544 files in total.
15924 relevant lines, 11567 lines covered and 4357 lines missed. ( 72.64% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
card-mod-bootstrap/lib/card/lazy_tab.rb 95.00 % 37 20 19 1 29.40
card-mod-bootstrap/lib/card/tab.rb 100.00 % 76 40 40 0 67.73
card-mod-follow/lib/card/follower_stash.rb 97.83 % 88 46 45 1 35.52
card-mod-history/lib/card/act.rb 93.18 % 137 44 41 3 163.57
card-mod-history/lib/card/act/act_renderer.rb 89.89 % 217 89 80 9 3.83
card-mod-history/lib/card/act/act_renderer/absolute_act_renderer.rb 100.00 % 34 13 13 0 1.00
card-mod-history/lib/card/act/act_renderer/bridge_act_renderer.rb 66.67 % 53 27 18 9 0.67
card-mod-history/lib/card/act/act_renderer/relative_act_renderer.rb 80.77 % 59 26 21 5 1.19
card-mod-history/lib/card/action.rb 96.20 % 230 79 76 3 429.80
card-mod-history/lib/card/action/action_renderer.rb 93.62 % 94 47 44 3 3.40
card-mod-history/lib/card/action/admin.rb 57.89 % 36 19 11 8 0.58
card-mod-history/lib/card/action/differ.rb 90.00 % 89 40 36 4 12.53
card-mod-history/lib/card/change.rb 94.44 % 70 18 17 1 236.22
card-mod-machines/lib/card/machine.rb 57.89 % 33 19 11 8 6.26
card-mod-tinymce_editor/lib/card/reference/nest_parser.rb 97.44 % 74 39 38 1 13.05
card-mod-virtual/lib/card/virtual.rb 88.46 % 95 52 46 6 107.12
card/lib/card/auth.rb 88.89 % 45 18 16 2 4.06
card/lib/card/auth/current.rb 91.78 % 158 73 67 6 978.62
card/lib/card/auth/permissions.rb 96.88 % 72 32 31 1 3620.63
card/lib/card/auth/proxy.rb 100.00 % 59 27 27 0 5554.30
card/lib/card/auth/setup.rb 71.43 % 55 28 20 8 3.32
card/lib/card/auth/token.rb 84.21 % 38 19 16 3 8.47
card/lib/card/cache/persistent.rb 76.56 % 154 64 49 15 5.94
card/lib/card/content.rb 86.11 % 153 72 62 10 1075.51
card/lib/card/content/chunk.rb 95.65 % 96 46 44 2 784.98
card/lib/card/content/chunk/abstract.rb 95.24 % 88 42 40 2 1818.88
card/lib/card/content/clean.rb 100.00 % 95 50 50 0 344.08
card/lib/card/content/diff.rb 100.00 % 70 33 33 0 13.94
card/lib/card/content/diff/l_c_s.rb 97.96 % 90 49 48 1 31.90
card/lib/card/content/diff/l_c_s/processor.rb 93.55 % 163 93 87 6 22.62
card/lib/card/content/diff/result.rb 91.49 % 159 94 86 8 12.19
card/lib/card/content/parser.rb 100.00 % 104 49 49 0 3959.45
card/lib/card/content/truncate.rb 26.32 % 67 38 10 28 0.26
card/lib/card/director/subdirector_array.rb 100.00 % 51 29 29 0 1022.45
card/lib/card/env/success.rb 90.22 % 171 92 83 9 41.79
card/lib/card/error.rb 92.94 % 173 85 79 6 7.14
card/lib/card/format/nest.rb 100.00 % 81 39 39 0 4474.59
card/lib/card/format/nest/fetch.rb 100.00 % 75 41 41 0 840.78
card/lib/card/mailer.rb 100.00 % 38 18 18 0 40.33
card/lib/card/migration.rb 37.04 % 159 81 30 51 0.67
card/lib/card/migration/core.rb 100.00 % 11 5 5 0 1.00
card/lib/card/migration/import.rb 71.43 % 119 49 35 14 2.22
card/lib/card/migration/import/import_data.rb 84.62 % 118 65 55 10 4.80
card/lib/card/migration/import/import_data/card_attributes.rb 88.57 % 64 35 31 4 8.37
card/lib/card/migration/import/import_data/card_content.rb 93.75 % 30 16 15 1 3.06
card/lib/card/migration/import/merger.rb 100.00 % 36 20 20 0 1.00
card/lib/card/mod/load_strategy/eval.rb 100.00 % 16 8 8 0 65.38
card/lib/card/query.rb 100.00 % 110 23 23 0 1221.35
card/lib/card/query/abstract_query.rb 100.00 % 95 48 48 0 4664.60
card/lib/card/query/abstract_query/query_helper.rb 100.00 % 56 30 30 0 5402.63
card/lib/card/query/abstract_query/tie.rb 100.00 % 104 52 52 0 2109.19
card/lib/card/query/act_query.rb 100.00 % 26 13 13 0 66.31
card/lib/card/query/action_query.rb 100.00 % 36 19 19 0 48.32
card/lib/card/query/card_query.rb 100.00 % 59 30 30 0 1432.70
card/lib/card/query/card_query/conjunctions.rb 100.00 % 48 26 26 0 328.15
card/lib/card/query/card_query/found_by.rb 95.24 % 43 21 20 1 11.71
card/lib/card/query/card_query/interpretation.rb 95.92 % 100 49 47 2 3059.51
card/lib/card/query/card_query/match_attributes.rb 100.00 % 44 20 20 0 6.25
card/lib/card/query/card_query/normalization.rb 90.91 % 60 33 30 3 3534.88
card/lib/card/query/card_query/reference_attributes.rb 100.00 % 45 15 15 0 169.40
card/lib/card/query/card_query/relational_attributes.rb 100.00 % 95 45 45 0 90.58
card/lib/card/query/card_query/run.rb 90.00 % 112 60 54 6 3255.65
card/lib/card/query/card_query/sorting.rb 97.96 % 101 49 48 1 1.10
card/lib/card/query/clause.rb 100.00 % 19 9 9 0 1816.78
card/lib/card/query/join.rb 84.00 % 126 50 42 8 3334.66
card/lib/card/query/reference_query.rb 93.33 % 54 30 28 2 1257.97
card/lib/card/query/sql_statement.rb 98.48 % 120 66 65 1 2280.77
card/lib/card/query/sql_statement/joins.rb 100.00 % 62 37 37 0 2649.92
card/lib/card/query/sql_statement/order.rb 100.00 % 68 30 30 0 2185.10
card/lib/card/query/sql_statement/where.rb 100.00 % 102 54 54 0 3257.19
card/lib/card/query/value.rb 94.34 % 94 53 50 3 1755.40
card/lib/card/query/value/match_value.rb 96.77 % 65 31 30 1 21.03
card/lib/card/reference.rb 58.82 % 85 34 20 14 427.44
card/lib/card/seed_consts.rb 87.50 % 20 8 7 1 0.88
card/lib/card/set/type.rb 100.00 % 46 26 26 0 898.69
card/lib/card/subcards.rb 91.07 % 114 56 51 5 1964.20
card/lib/card/subcards/add.rb 88.33 % 120 60 53 7 519.82
card/lib/card/subcards/relate.rb 92.86 % 27 14 13 1 22.07
card/lib/card/subcards/remove.rb 66.67 % 44 27 18 9 0.67
card/lib/card/version.rb 100.00 % 11 5 5 0 7.00
card/lib/card/view.rb 93.18 % 119 44 41 3 12225.00
card/lib/card/view/cache.rb 89.29 % 298 56 50 6 722.20
card/lib/card/view/cache/cache_action.rb 72.73 % 121 44 32 12 3668.27
card/lib/card/view/cache/stub.rb 60.00 % 46 15 9 6 0.60
card/lib/card/view/classy.rb 78.26 % 168 69 54 15 5675.77
card/lib/card/view/options.rb 100.00 % 93 15 15 0 1.00
card/lib/card/view/options/key_lists.rb 100.00 % 45 18 18 0 3945.72
card/lib/card/view/options/visibility.rb 93.18 % 99 44 41 3 11089.23
card/lib/card/view/options/voo_api.rb 94.44 % 204 90 85 5 17850.03
card/lib/card/view/permission.rb 100.00 % 54 25 25 0 11959.56
card/mod/core/chunk/escaped_literal.rb 100.00 % 27 10 10 0 1.80
card/mod/core/chunk/keep_escaped_literal.rb 100.00 % 26 10 10 0 1.20
card/mod/core/chunk/link.rb 95.16 % 121 62 59 3 539.79
card/mod/core/chunk/nest.rb 92.42 % 127 66 61 5 1142.06
card/mod/core/chunk/query_reference.rb 96.30 % 95 27 26 1 85.00
card/mod/core/chunk/reference.rb 90.00 % 59 30 27 3 1567.60
card/mod/core/chunk/uri.rb 98.11 % 145 53 52 1 72.06
card/mod/core/chunk/view_stub.rb 48.39 % 62 31 15 16 0.48
card/mod/core/lib/card/rule/preference_cache.rb 100.00 % 74 30 30 0 274.57
card/mod/core/lib/card/rule/read_rule_cache.rb 100.00 % 30 11 11 0 453.45
card/mod/standard/lib/card/layout/card_layout.rb 95.65 % 44 23 22 1 6.96
card/mod/standard/lib/card/layout/code_layout.rb 80.00 % 9 5 4 1 0.80
card/mod/standard/lib/card/layout/unknown_layout.rb 70.00 % 20 10 7 3 0.70
card/tmpsets/set/mod001-utility/abstract/bs_badge.rb 56.25 % 31 16 9 7 0.75
card/tmpsets/set/mod001-utility/abstract/filterable.rb 53.85 % 22 13 7 6 0.77
card/tmpsets/set/mod001-utility/abstract/filterable_bar.rb 63.64 % 20 11 7 4 0.82
card/tmpsets/set/mod001-utility/abstract/utility.rb 60.00 % 22 10 6 4 0.80
card/tmpsets/set/mod002-admin/self/admin.rb 28.77 % 152 73 21 52 0.33
card/tmpsets/set/mod002-admin/self/admin_info.rb 52.00 % 57 25 13 12 0.64
card/tmpsets/set/mod002-admin/self/debugger.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod002-admin/self/trash.rb 48.00 % 72 25 12 13 0.60
card/tmpsets/set/mod002-admin/self/version.rb 100.00 % 22 8 8 0 6.75
card/tmpsets/set/mod003-core/abstract/code_file.rb 78.00 % 93 50 39 11 6.82
card/tmpsets/set/mod003-core/abstract/haml_file.rb 58.82 % 33 17 10 7 0.76
card/tmpsets/set/mod003-core/abstract/lock.rb 100.00 % 35 19 19 0 1.32
card/tmpsets/set/mod003-core/abstract/vendor_code_file.rb 90.00 % 19 10 9 1 1.10
card/tmpsets/set/mod003-core/all/abort.rb 75.00 % 85 44 33 11 114.50
card/tmpsets/set/mod003-core/all/actify.rb 100.00 % 77 43 43 0 164.56
card/tmpsets/set/mod003-core/all/active_card.rb 100.00 % 15 7 7 0 21.29
card/tmpsets/set/mod003-core/all/assign_attributes.rb 98.73 % 135 79 78 1 1954.10
card/tmpsets/set/mod003-core/all/cache.rb 82.09 % 118 67 55 12 2584.51
card/tmpsets/set/mod003-core/all/chunk.rb 37.35 % 151 83 31 52 0.64
card/tmpsets/set/mod003-core/all/codename.rb 66.67 % 38 21 14 7 59.05
card/tmpsets/set/mod003-core/all/collection.rb 66.67 % 64 33 22 11 44.12
card/tmpsets/set/mod003-core/all/content.rb 75.00 % 187 92 69 23 120.36
card/tmpsets/set/mod003-core/all/contextual_content.rb 100.00 % 37 20 20 0 147.60
card/tmpsets/set/mod003-core/all/debug.rb 100.00 % 32 19 19 0 7.05
card/tmpsets/set/mod003-core/all/event_conditions.rb 79.35 % 181 92 73 19 5801.55
card/tmpsets/set/mod003-core/all/export.rb 40.00 % 77 40 16 24 0.48
card/tmpsets/set/mod003-core/all/extended.rb 92.00 % 58 25 23 2 10.56
card/tmpsets/set/mod003-core/all/fetch.rb 79.59 % 131 49 39 10 3332.22
card/tmpsets/set/mod003-core/all/fetch_helper.rb 100.00 % 44 22 22 0 18.09
card/tmpsets/set/mod003-core/all/haml.rb 75.86 % 84 29 22 7 28.72
card/tmpsets/set/mod003-core/all/i18n.rb 100.00 % 19 9 9 0 6.44
card/tmpsets/set/mod003-core/all/initialize.rb 100.00 % 85 49 49 0 2564.63
card/tmpsets/set/mod003-core/all/item.rb 45.45 % 139 77 35 42 6.06
card/tmpsets/set/mod003-core/all/layouts.rb 64.71 % 43 17 11 6 0.82
card/tmpsets/set/mod003-core/all/location_history.rb 100.00 % 28 14 14 0 16.93
card/tmpsets/set/mod003-core/all/name.rb 90.23 % 248 133 120 13 1839.16
card/tmpsets/set/mod003-core/all/name_events.rb 80.26 % 143 76 61 15 66.00
card/tmpsets/set/mod003-core/all/observer.rb 93.75 % 31 16 15 1 108.44
card/tmpsets/set/mod003-core/all/pattern.rb 93.94 % 63 33 31 2 3408.73
card/tmpsets/set/mod003-core/all/permissions.rb 88.80 % 242 125 111 14 263.35
card/tmpsets/set/mod003-core/all/references.rb 93.55 % 200 93 87 6 85.77
card/tmpsets/set/mod003-core/all/rename.rb 96.30 % 42 27 26 1 10.41
card/tmpsets/set/mod003-core/all/rules.rb 78.26 % 90 46 36 10 2428.00
card/tmpsets/set/mod003-core/all/states.rb 80.00 % 93 35 28 7 2583.60
card/tmpsets/set/mod003-core/all/subcards.rb 73.13 % 128 67 49 18 170.27
card/tmpsets/set/mod003-core/all/tabs.rb 40.00 % 60 30 12 18 0.50
card/tmpsets/set/mod003-core/all/templating.rb 92.50 % 80 40 37 3 732.60
card/tmpsets/set/mod003-core/all/trash.rb 63.77 % 136 69 44 25 23.62
card/tmpsets/set/mod003-core/all/type.rb 88.24 % 70 34 30 4 706.56
card/tmpsets/set/mod003-core/all/update_read_rules.rb 100.00 % 21 9 9 0 72.67
card/tmpsets/set/mod003-core/all/utils.rb 35.19 % 101 54 19 35 1.70
card/tmpsets/set/mod004-card-mod-format/all/all_css.rb 54.17 % 46 24 13 11 0.67
card/tmpsets/set/mod004-card-mod-format/all/all_csv.rb 38.89 % 102 54 21 33 0.44
card/tmpsets/set/mod004-card-mod-format/all/all_js.rb 77.78 % 19 9 7 2 1.11
card/tmpsets/set/mod004-card-mod-format/all/base.rb 76.39 % 146 72 55 17 19.47
card/tmpsets/set/mod004-card-mod-format/all/file.rb 77.78 % 18 9 7 2 1.11
card/tmpsets/set/mod004-card-mod-format/all/head.rb 93.42 % 157 76 71 5 24.92
card/tmpsets/set/mod004-card-mod-format/all/json.rb 41.10 % 164 73 30 43 0.45
card/tmpsets/set/mod004-card-mod-format/all/rss.rb 45.83 % 85 48 22 26 0.52
card/tmpsets/set/mod004-card-mod-format/all/text.rb 100.00 % 16 7 7 0 1.86
card/tmpsets/set/mod004-card-mod-format/self/head.rb 91.67 % 31 12 11 1 6.67
card/tmpsets/set/mod004-card-mod-format/type/html.rb 72.22 % 36 18 13 5 7.28
card/tmpsets/set/mod004-card-mod-format/type/json.rb 70.83 % 50 24 17 7 1.96
card/tmpsets/set/mod004-card-mod-format/type/plain_text.rb 77.78 % 18 9 7 2 1.11
card/tmpsets/set/mod005-pointer/abstract/00_paging_params.rb 85.00 % 40 20 17 3 1.15
card/tmpsets/set/mod005-pointer/abstract/01_paging.rb 41.89 % 156 74 31 43 0.49
card/tmpsets/set/mod005-pointer/abstract/01_paging/paging_links.rb 41.86 % 98 43 18 25 0.47
card/tmpsets/set/mod005-pointer/abstract/02_items.rb 78.16 % 207 87 68 19 418.05
card/tmpsets/set/mod005-pointer/abstract/02_pointer.rb 80.00 % 19 10 8 2 1.00
card/tmpsets/set/mod005-pointer/abstract/02_pointer/events.rb 57.89 % 80 38 22 16 6.03
card/tmpsets/set/mod005-pointer/abstract/02_pointer/html_views.rb 49.18 % 134 61 30 31 0.80
card/tmpsets/set/mod005-pointer/abstract/02_pointer/html_views/filter.rb 46.88 % 71 32 15 17 0.66
card/tmpsets/set/mod005-pointer/abstract/02_pointer/options_api.rb 48.84 % 87 43 21 22 1.05
card/tmpsets/set/mod005-pointer/abstract/02_pointer/other_views.rb 56.00 % 111 50 28 22 0.74
card/tmpsets/set/mod005-pointer/abstract/code_pointer.rb 85.00 % 44 20 17 3 5.75
card/tmpsets/set/mod005-pointer/abstract/id_pointer.rb 50.00 % 30 14 7 7 0.64
card/tmpsets/set/mod005-pointer/right/content_options.rb 71.43 % 13 7 5 2 1.00
card/tmpsets/set/mod005-pointer/self/input_options.rb 92.86 % 22 14 13 1 1.07
card/tmpsets/set/mod005-pointer/self/script_editors.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod005-pointer/self/script_libraries.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod005-pointer/self/script_mods.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod005-pointer/self/script_pointer_config.rb 88.89 % 18 9 8 1 1.11
card/tmpsets/set/mod005-pointer/self/style_libraries.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod005-pointer/self/style_mods.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod005-pointer/type/link_list.rb 53.85 % 49 26 14 12 0.69
card/tmpsets/set/mod005-pointer/type/list.rb 76.92 % 25 13 10 3 13.54
card/tmpsets/set/mod005-pointer/type/mirror_list.rb 36.73 % 102 49 18 31 0.41
card/tmpsets/set/mod005-pointer/type/mirrored_list.rb 31.75 % 121 63 20 43 0.35
card/tmpsets/set/mod005-pointer/type/nest_list.rb 53.33 % 55 30 16 14 0.67
card/tmpsets/set/mod005-pointer/type/pointer.rb 70.00 % 19 10 7 3 1.00
card/tmpsets/set/mod006-card-mod-virtual/abstract/virtual_cache.rb 79.17 % 52 24 19 5 0.96
card/tmpsets/set/mod007-card-mod-machines/abstract/machine.rb 84.68 % 230 111 94 17 3.23
card/tmpsets/set/mod007-card-mod-machines/abstract/machine/output_cache.rb 100.00 % 25 12 12 0 1.42
card/tmpsets/set/mod007-card-mod-machines/abstract/machine/output_update.rb 82.98 % 77 47 39 8 4.96
card/tmpsets/set/mod007-card-mod-machines/abstract/machine_input.rb 68.29 % 81 41 28 13 1.68
card/tmpsets/set/mod007-card-mod-machines/abstract/script.rb 56.82 % 93 44 25 19 0.75
card/tmpsets/set/mod007-card-mod-machines/abstract/skin_box.rb 52.38 % 42 21 11 10 0.71
card/tmpsets/set/mod007-card-mod-machines/all/reset_machines.rb 38.89 % 31 18 7 11 0.50
card/tmpsets/set/mod007-card-mod-machines/right/machine_cache.rb 85.71 % 14 7 6 1 1.14
card/tmpsets/set/mod007-card-mod-machines/right/machine_input.rb 100.00 % 16 8 8 0 1.75
card/tmpsets/set/mod007-card-mod-machines/right/machine_output.rb 88.89 % 53 27 24 3 1.19
card/tmpsets/set/mod007-card-mod-machines/self/script_decko.rb 75.00 % 21 8 6 2 1.00
card/tmpsets/set/mod007-card-mod-machines/self/script_html5shiv_printshiv.rb 100.00 % 20 8 8 0 4.13
card/tmpsets/set/mod007-card-mod-machines/self/script_jquery.rb 77.78 % 19 9 7 2 1.00
card/tmpsets/set/mod007-card-mod-machines/self/script_jquery_helper.rb 87.50 % 23 8 7 1 1.13
card/tmpsets/set/mod007-card-mod-machines/self/style_bootstrap_compatible.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod007-card-mod-machines/self/style_cards.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod007-card-mod-machines/self/style_jquery_ui_smoothness.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod007-card-mod-machines/type/coffee_script.rb 64.71 % 34 17 11 6 0.88
card/tmpsets/set/mod007-card-mod-machines/type/css.rb 69.05 % 94 42 29 13 0.81
card/tmpsets/set/mod007-card-mod-machines/type/java_script.rb 87.50 % 18 8 7 1 1.25
card/tmpsets/set/mod007-card-mod-machines/type/scss.rb 85.71 % 30 14 12 2 1.14
card/tmpsets/set/mod007-card-mod-machines/type/skin.rb 88.89 % 18 9 8 1 1.11
card/tmpsets/set/mod008-settings/abstract/permission.rb 37.93 % 131 58 22 36 22.90
card/tmpsets/set/mod008-settings/abstract/templated_nests.rb 75.00 % 16 8 6 2 1.13
card/tmpsets/set/mod008-settings/all/supports_content_options.rb 75.00 % 16 8 6 2 1.00
card/tmpsets/set/mod008-settings/right/autoname.rb 100.00 % 12 6 6 0 1.50
card/tmpsets/set/mod008-settings/right/comment.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod008-settings/right/content_option_view.rb 66.67 % 19 9 6 3 1.00
card/tmpsets/set/mod008-settings/right/content_options.rb 61.54 % 27 13 8 5 0.85
card/tmpsets/set/mod008-settings/right/create.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod008-settings/right/default.rb 52.38 % 43 21 11 10 0.67
card/tmpsets/set/mod008-settings/right/delete.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod008-settings/right/guide.rb 85.71 % 17 7 6 1 1.29
card/tmpsets/set/mod008-settings/right/help.rb 72.73 % 24 11 8 3 1.00
card/tmpsets/set/mod008-settings/right/input_type.rb 60.00 % 44 20 12 8 0.75
card/tmpsets/set/mod008-settings/right/read.rb 97.73 % 88 44 43 1 2.09
card/tmpsets/set/mod008-settings/right/script.rb 84.62 % 28 13 11 2 1.08
card/tmpsets/set/mod008-settings/right/structure.rb 42.50 % 81 40 17 23 0.53
card/tmpsets/set/mod008-settings/right/style.rb 58.82 % 65 34 20 14 1.44
card/tmpsets/set/mod008-settings/right/update.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod008-settings/self/autoname.rb 100.00 % 13 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/captcha.rb 100.00 % 14 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/content_option_view.rb 85.71 % 19 7 6 1 1.14
card/tmpsets/set/mod008-settings/self/content_options.rb 85.71 % 19 7 6 1 1.14
card/tmpsets/set/mod008-settings/self/create.rb 100.00 % 13 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/csv_structure.rb 100.00 % 11 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/default.rb 100.00 % 12 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/default_html_view.rb 100.00 % 11 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/delete.rb 100.00 % 13 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/follow_fields.rb 100.00 % 11 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/guide.rb 100.00 % 12 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/head.rb 100.00 % 13 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/help.rb 100.00 % 14 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/input_type.rb 88.89 % 22 9 8 1 1.22
card/tmpsets/set/mod008-settings/self/layout.rb 100.00 % 13 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/on_create.rb 100.00 % 12 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/on_delete.rb 100.00 % 12 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/on_update.rb 100.00 % 12 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/read.rb 100.00 % 13 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/recent_settings.rb 87.50 % 16 8 7 1 4.75
card/tmpsets/set/mod008-settings/self/script.rb 100.00 % 11 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/structure.rb 100.00 % 14 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/style.rb 100.00 % 13 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/table_of_contents.rb 100.00 % 14 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/thanks.rb 100.00 % 14 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/update.rb 100.00 % 13 6 6 0 1.33
card/tmpsets/set/mod008-settings/type/setting.rb 48.48 % 88 33 16 17 0.64
card/tmpsets/set/mod009-card-mod-search/abstract/00_filter_helper.rb 76.67 % 64 30 23 7 18.13
card/tmpsets/set/mod009-card-mod-search/abstract/02_search_params.rb 75.76 % 67 33 25 8 0.97
card/tmpsets/set/mod009-card-mod-search/abstract/03_filter.rb 75.00 % 32 16 12 4 1.06
card/tmpsets/set/mod009-card-mod-search/abstract/03_filter/filter_form.rb 44.44 % 107 45 20 25 0.53
card/tmpsets/set/mod009-card-mod-search/abstract/03_filter/form_helper.rb 35.94 % 114 64 23 41 0.42
card/tmpsets/set/mod009-card-mod-search/abstract/03_filter/query_construction.rb 68.18 % 45 22 15 7 10.91
card/tmpsets/set/mod009-card-mod-search/abstract/04_right_filter_form.rb 68.75 % 35 16 11 5 0.88
card/tmpsets/set/mod009-card-mod-search/abstract/05_search.rb 62.75 % 93 51 32 19 0.88
card/tmpsets/set/mod009-card-mod-search/abstract/05_search/views.rb 45.35 % 168 86 39 47 0.55
card/tmpsets/set/mod009-card-mod-search/abstract/06_cql_search.rb 88.89 % 117 63 56 7 135.22
card/tmpsets/set/mod009-card-mod-search/right/children.rb 83.33 % 13 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/created.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/edited.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/editors.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/follow.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/linked_to_by.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/links_to.rb 83.33 % 14 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/mates.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/nested_by.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/nests.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/referred_to_by.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/refers_to.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/self/recent.rb 66.67 % 44 24 16 8 2.71
card/tmpsets/set/mod009-card-mod-search/self/search.rb 42.31 % 105 52 22 30 0.52
card/tmpsets/set/mod009-card-mod-search/type/search_type.rb 54.35 % 89 46 25 21 1.09
card/tmpsets/set/mod010-standard/all/comment.rb 44.44 % 89 45 20 25 7.67
card/tmpsets/set/mod010-standard/all/error.rb 59.09 % 85 44 26 18 0.68
card/tmpsets/set/mod010-standard/all/links.rb 91.55 % 158 71 65 6 85.52
card/tmpsets/set/mod010-standard/all/list_changes.rb 80.77 % 58 26 21 5 26.92
card/tmpsets/set/mod010-standard/all/path.rb 89.61 % 184 77 69 8 125.23
card/tmpsets/set/mod010-standard/all/rich_html.rb 100.00 % 13 6 6 0 1.50
card/tmpsets/set/mod010-standard/all/rich_html/alert.rb 100.00 % 32 17 17 0 6.53
card/tmpsets/set/mod010-standard/all/rich_html/content.rb 62.89 % 177 97 61 36 3.76
card/tmpsets/set/mod010-standard/all/rich_html/error.rb 84.69 % 204 98 83 15 2.09
card/tmpsets/set/mod010-standard/all/rich_html/frame.rb 96.97 % 62 33 32 1 11.15
card/tmpsets/set/mod010-standard/all/rich_html/header.rb 88.89 % 70 36 32 4 6.33
card/tmpsets/set/mod010-standard/all/rich_html/html_views/guide.rb 81.82 % 60 33 27 6 6.61
card/tmpsets/set/mod010-standard/all/rich_html/html_views/help.rb 77.42 % 58 31 24 7 5.16
card/tmpsets/set/mod010-standard/all/rich_html/html_views/info.rb 38.10 % 93 42 16 26 0.60
card/tmpsets/set/mod010-standard/all/rich_html/html_views/size.rb 61.54 % 26 13 8 5 1.00
card/tmpsets/set/mod010-standard/all/rich_html/menu.rb 78.57 % 138 70 55 15 2.94
card/tmpsets/set/mod010-standard/all/rich_html/modal.rb 73.85 % 128 65 48 17 1.02
card/tmpsets/set/mod010-standard/all/rich_html/overlay.rb 37.10 % 113 62 23 39 0.44
card/tmpsets/set/mod010-standard/all/rich_html/process_layout.rb 72.09 % 80 43 31 12 15.40
card/tmpsets/set/mod010-standard/all/rich_html/show.rb 84.00 % 54 25 21 4 7.72
card/tmpsets/set/mod010-standard/all/rich_html/title.rb 89.29 % 56 28 25 3 45.86
card/tmpsets/set/mod010-standard/all/rich_html/wrapper.rb 86.59 % 156 82 71 11 97.32
card/tmpsets/set/mod010-standard/right/discussion.rb 60.00 % 18 10 6 4 0.80
card/tmpsets/set/mod010-standard/right/head.rb 84.62 % 26 13 11 2 4.46
card/tmpsets/set/mod010-standard/right/type_plus_right.rb 83.33 % 13 6 5 1 1.17
card/tmpsets/set/mod010-standard/right/when_created.rb 71.43 % 15 7 5 2 1.00
card/tmpsets/set/mod010-standard/right/when_last_edited.rb 71.43 % 15 7 5 2 1.00
card/tmpsets/set/mod010-standard/self/alerts.rb 83.33 % 14 6 5 1 1.17
card/tmpsets/set/mod010-standard/self/cardtype.rb 52.63 % 51 19 10 9 3.05
card/tmpsets/set/mod010-standard/self/codenames.rb 100.00 % 10 4 4 0 1.50
card/tmpsets/set/mod010-standard/self/foot.rb 83.33 % 15 6 5 1 1.17
card/tmpsets/set/mod010-standard/self/home.rb 88.89 % 18 9 8 1 6.22
card/tmpsets/set/mod010-standard/self/now.rb 83.33 % 15 6 5 1 1.17
card/tmpsets/set/mod010-standard/self/sidebar.rb 83.33 % 14 6 5 1 1.17
card/tmpsets/set/mod010-standard/type/basic.rb 39.02 % 72 41 16 25 0.54
card/tmpsets/set/mod010-standard/type/cardtype.rb 70.27 % 136 74 52 22 0.81
card/tmpsets/set/mod010-standard/type/layout_type.rb 66.67 % 25 12 8 4 0.92
card/tmpsets/set/mod010-standard/type/notification_template.rb 60.87 % 42 23 14 9 0.74
card/tmpsets/set/mod010-standard/type/number.rb 53.33 % 31 15 8 7 0.73
card/tmpsets/set/mod010-standard/type/phrase.rb 85.71 % 14 7 6 1 1.29
card/tmpsets/set/mod010-standard/type/session.rb 69.44 % 70 36 25 11 9.67
card/tmpsets/set/mod010-standard/type/toggle.rb 54.17 % 47 24 13 11 0.67
card/tmpsets/set/mod010-standard/type/uri.rb 75.00 % 24 12 9 3 1.08
card/tmpsets/set/mod011-card-mod-email/abstract/email_field.rb 90.00 % 50 20 18 2 1.45
card/tmpsets/set/mod011-card-mod-email/abstract/test_context.rb 84.21 % 35 19 16 3 1.58
card/tmpsets/set/mod011-card-mod-email/all/email_html.rb 77.78 % 18 9 7 2 1.11
card/tmpsets/set/mod011-card-mod-email/all/email_text.rb 72.73 % 23 11 8 3 1.00
card/tmpsets/set/mod011-card-mod-email/right/bcc.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod011-card-mod-email/right/cc.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod011-card-mod-email/right/from.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod011-card-mod-email/right/html_message.rb 91.67 % 22 12 11 1 1.42
card/tmpsets/set/mod011-card-mod-email/right/subject.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod011-card-mod-email/right/text_message.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod011-card-mod-email/right/to.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod011-card-mod-email/type/email_template.rb 61.40 % 100 57 35 22 1.16
card/tmpsets/set/mod011-card-mod-email/type/email_template/email_config.rb 93.62 % 90 47 44 3 3.43
card/tmpsets/set/mod012-card-mod-account/abstract/account_field.rb 54.55 % 26 11 6 5 0.73
card/tmpsets/set/mod012-card-mod-account/abstract/accountable.rb 56.00 % 58 25 14 11 0.68
card/tmpsets/set/mod012-card-mod-account/all/account.rb 85.19 % 106 54 46 8 150.76
card/tmpsets/set/mod012-card-mod-account/right/account.rb 54.29 % 67 35 19 16 0.60
card/tmpsets/set/mod012-card-mod-account/right/account/events.rb 38.46 % 107 52 20 32 0.48
card/tmpsets/set/mod012-card-mod-account/right/account/views.rb 60.00 % 74 35 21 14 0.77
card/tmpsets/set/mod012-card-mod-account/right/api_key.rb 57.14 % 57 14 8 6 0.71
card/tmpsets/set/mod012-card-mod-account/right/email.rb 40.74 % 52 27 11 16 0.48
card/tmpsets/set/mod012-card-mod-account/right/password.rb 51.72 % 60 29 15 14 0.62
card/tmpsets/set/mod012-card-mod-account/right/roles.rb 36.84 % 36 19 7 12 0.47
card/tmpsets/set/mod012-card-mod-account/right/salt.rb 72.73 % 22 11 8 3 0.91
card/tmpsets/set/mod012-card-mod-account/right/status.rb 64.29 % 27 14 9 5 0.79
card/tmpsets/set/mod012-card-mod-account/self/signin.rb 34.45 % 235 119 41 78 0.37
card/tmpsets/set/mod012-card-mod-account/type/role.rb 60.00 % 30 15 9 6 0.80
card/tmpsets/set/mod012-card-mod-account/type/signup.rb 50.00 % 63 32 16 16 0.56
card/tmpsets/set/mod012-card-mod-account/type/signup/views.rb 41.82 % 102 55 23 32 0.51
card/tmpsets/set/mod012-card-mod-account/type/user.rb 50.00 % 77 36 18 18 0.58
card/tmpsets/set/mod012-card-mod-account/type_plus_right/user/email.rb 70.00 % 22 10 7 3 1.00
card/tmpsets/set/mod013-navbar/abstract/account_dropdown.rb 100.00 % 34 16 16 0 7.94
card/tmpsets/set/mod013-navbar/abstract/pointer/html_views.rb 100.00 % 14 7 7 0 4.71
card/tmpsets/set/mod013-navbar/all/navbar_links.rb 93.33 % 67 30 28 2 33.53
card/tmpsets/set/mod013-navbar/right/enabled_roles.rb 77.14 % 70 35 27 8 4.14
card/tmpsets/set/mod013-navbar/self/account_links.rb 85.71 % 108 49 42 7 12.37
card/tmpsets/set/mod013-navbar/self/dropdown_divider.rb 88.89 % 18 9 8 1 3.67
card/tmpsets/set/mod013-navbar/self/navbox.rb 100.00 % 45 18 18 0 9.72
card/tmpsets/set/mod013-navbar/type/html.rb 63.64 % 23 11 7 4 0.91
card/tmpsets/set/mod014-card-mod-edit/all/bridge.rb 73.53 % 73 34 25 9 0.82
card/tmpsets/set/mod014-card-mod-edit/all/bridge/bridge_pills.rb 38.71 % 56 31 12 19 0.52
card/tmpsets/set/mod014-card-mod-edit/all/bridge/follow_section.rb 47.62 % 46 21 10 11 0.67
card/tmpsets/set/mod014-card-mod-edit/all/bridge/related_section.rb 56.25 % 43 16 9 7 0.81
card/tmpsets/set/mod014-card-mod-edit/all/bridge/tab_views.rb 46.15 % 50 26 12 14 0.62
card/tmpsets/set/mod014-card-mod-edit/all/bridge/tab_visibility.rb 78.13 % 62 32 25 7 1.09
card/tmpsets/set/mod014-card-mod-edit/all/edit_content.rb 39.29 % 69 28 11 17 0.50
card/tmpsets/set/mod014-card-mod-edit/all/edit_inline.rb 57.14 % 65 28 16 12 2.25
card/tmpsets/set/mod014-card-mod-edit/all/edit_name.rb 45.16 % 67 31 14 17 0.55
card/tmpsets/set/mod014-card-mod-edit/all/edit_type.rb 74.07 % 110 54 40 14 16.46
card/tmpsets/set/mod014-card-mod-edit/all/editing.rb 46.88 % 100 32 15 17 0.56
card/tmpsets/set/mod014-card-mod-edit/all/editor.rb 83.33 % 65 30 25 5 4.10
card/tmpsets/set/mod014-card-mod-edit/all/form.rb 79.34 % 254 121 96 25 8.29
card/tmpsets/set/mod014-card-mod-edit/all/form_buttons.rb 42.86 % 73 42 18 24 0.83
card/tmpsets/set/mod014-card-mod-edit/all/form_elements.rb 90.48 % 80 42 38 4 12.55
card/tmpsets/set/mod014-card-mod-edit/all/formgroup.rb 88.89 % 46 27 24 3 9.81
card/tmpsets/set/mod014-card-mod-edit/all/new.rb 79.79 % 197 94 75 19 3.57
card/tmpsets/set/mod014-card-mod-edit/all/overlay_guide.rb 100.00 % 18 6 6 0 1.67
card/tmpsets/set/mod014-card-mod-edit/all/template_nest.rb 33.33 % 51 27 9 18 0.44
card/tmpsets/set/mod014-card-mod-edit/type/list.rb 66.67 % 24 12 8 4 0.83
card/tmpsets/set/mod014-card-mod-edit/type/plain_text.rb 72.73 % 22 11 8 3 1.00
card/tmpsets/set/mod014-card-mod-edit/type/pointer.rb 70.00 % 20 10 7 3 0.90
card/tmpsets/set/mod015-card-mod-ace_editor/all/ace_editor.rb 77.78 % 21 9 7 2 1.11
card/tmpsets/set/mod015-card-mod-ace_editor/self/ace.rb 85.71 % 16 7 6 1 1.29
card/tmpsets/set/mod015-card-mod-ace_editor/self/script_ace.rb 100.00 % 13 7 7 0 1.29
card/tmpsets/set/mod015-card-mod-ace_editor/self/script_ace_config.rb 100.00 % 13 7 7 0 1.29
card/tmpsets/set/mod016-card-mod-bar_and_box/abstract/media.rb 64.29 % 26 14 9 5 0.86
card/tmpsets/set/mod016-card-mod-bar_and_box/all/bar.rb 81.67 % 114 60 49 11 9.05
card/tmpsets/set/mod016-card-mod-bar_and_box/all/box.rb 66.67 % 25 12 8 4 0.92
card/tmpsets/set/mod016-card-mod-bar_and_box/self/style_media.rb 100.00 % 15 8 8 0 1.38
card/tmpsets/set/mod016-card-mod-bar_and_box/type/image.rb 59.09 % 47 22 13 9 0.73
card/tmpsets/set/mod017-card-mod-bootstrap/abstract/bootstrap_code_file.rb 94.29 % 66 35 33 2 12.91
card/tmpsets/set/mod017-card-mod-bootstrap/abstract/bootswatch_theme.rb 87.50 % 166 56 49 7 1.64
card/tmpsets/set/mod017-card-mod-bootstrap/abstract/bootswatch_theme/html_views.rb 60.00 % 39 20 12 8 0.80
card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/accordion.rb 28.57 % 72 28 8 20 0.43
card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/dropdown.rb 82.35 % 95 34 28 6 11.85
card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/form.rb 100.00 % 44 23 23 0 7.96
card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/helper.rb 40.00 % 62 40 16 24 1.00
card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/icon.rb 91.18 % 118 34 31 3 7.88
card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/navbar.rb 33.33 % 75 33 11 22 0.45
card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/table.rb 29.09 % 108 55 16 39 0.36
card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/tabs.rb 100.00 % 49 9 9 0 1.44
card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/wrapper.rb 93.33 % 28 15 14 1 8.80
card/tmpsets/set/mod017-card-mod-bootstrap/all/rich_bootstrap.rb 83.33 % 24 12 10 2 1.08
card/tmpsets/set/mod017-card-mod-bootstrap/self/bootstrap_core.rb 100.00 % 22 11 11 0 3.82
card/tmpsets/set/mod017-card-mod-bootstrap/self/bootstrap_functions.rb 100.00 % 14 7 7 0 1.29
card/tmpsets/set/mod017-card-mod-bootstrap/self/font_awesome.rb 100.00 % 11 6 6 0 1.33
card/tmpsets/set/mod017-card-mod-bootstrap/self/material_icons.rb 100.00 % 11 6 6 0 1.33
card/tmpsets/set/mod017-card-mod-bootstrap/self/script_bootstrap.rb 80.00 % 21 10 8 2 1.00
card/tmpsets/set/mod017-card-mod-bootstrap/self/script_load_select2.rb 100.00 % 11 6 6 0 1.33
card/tmpsets/set/mod017-card-mod-bootstrap/self/script_select2.rb 80.00 % 21 10 8 2 1.00
card/tmpsets/set/mod017-card-mod-bootstrap/self/smartmenu_css.rb 85.71 % 14 7 6 1 1.14
card/tmpsets/set/mod017-card-mod-bootstrap/self/smartmenu_js.rb 85.71 % 14 7 6 1 1.14
card/tmpsets/set/mod017-card-mod-bootstrap/self/style_bootstrap_cards.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod017-card-mod-bootstrap/self/style_bootstrap_colorpicker.rb 100.00 % 15 8 8 0 1.25
card/tmpsets/set/mod017-card-mod-bootstrap/self/style_select2.rb 100.00 % 19 10 10 0 1.60
card/tmpsets/set/mod017-card-mod-bootstrap/self/style_select2_bootstrap.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod017-card-mod-bootstrap/type/bootswatch_skin.rb 100.00 % 24 9 9 0 1.22
card/tmpsets/set/mod017-card-mod-bootstrap/type/customized_bootswatch_skin.rb 41.18 % 124 68 28 40 0.46
card/tmpsets/set/mod017-card-mod-bootstrap/type/customized_bootswatch_skin/html_views.rb 65.22 % 45 23 15 8 0.87
card/tmpsets/set/mod017-card-mod-bootstrap/type_plus_right/customized_bootswatch_skin/colors.rb 44.23 % 122 52 23 29 0.56
card/tmpsets/set/mod018-card-mod-history/all/history.rb 75.00 % 118 56 42 14 115.54
card/tmpsets/set/mod018-card-mod-history/all/history/act_listing.rb 36.76 % 133 68 25 43 0.43
card/tmpsets/set/mod018-card-mod-history/all/history/actions.rb 46.27 % 133 67 31 36 9.40
card/tmpsets/set/mod018-card-mod-history/all/history/acts.rb 75.00 % 17 8 6 2 1.13
card/tmpsets/set/mod018-card-mod-history/all/history/events.rb 84.00 % 109 50 42 8 126.76
card/tmpsets/set/mod018-card-mod-history/all/history/last.rb 65.45 % 107 55 36 19 0.82
card/tmpsets/set/mod018-card-mod-history/all/history/revision.rb 40.00 % 74 40 16 24 5.35
card/tmpsets/set/mod018-card-mod-history/all/history/selected.rb 56.41 % 73 39 22 17 75.72
card/tmpsets/set/mod018-card-mod-history/all/history/views.rb 50.00 % 44 22 11 11 0.68
card/tmpsets/set/mod018-card-mod-history/all/history_bridge.rb 31.71 % 74 41 13 28 0.39
card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment.rb 67.19 % 121 64 43 21 7.36
card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/cloud.rb 35.62 % 142 73 26 47 1.42
card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/coded.rb 56.25 % 31 16 9 7 1.56
card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/local.rb 96.43 % 49 28 27 1 2.57
card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/paths.rb 91.43 % 67 35 32 3 64.74
card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/storage_type.rb 64.89 % 179 94 61 33 61.15
card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/upload_cache.rb 46.94 % 94 49 23 26 1.08
card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/web.rb 83.33 % 12 6 5 1 1.33
card/tmpsets/set/mod019-card-mod-carrierwave/all/file_utils.rb 63.64 % 50 22 14 8 1.00
card/tmpsets/set/mod019-card-mod-carrierwave/self/admin.rb 60.00 % 32 10 6 4 0.80
card/tmpsets/set/mod019-card-mod-carrierwave/self/favicon.rb 92.31 % 25 13 12 1 7.92
card/tmpsets/set/mod019-card-mod-carrierwave/self/new_file.rb 72.73 % 22 11 8 3 1.00
card/tmpsets/set/mod019-card-mod-carrierwave/self/new_image.rb 72.73 % 22 11 8 3 1.00
card/tmpsets/set/mod019-card-mod-carrierwave/type/file.rb 77.27 % 125 66 51 15 4.94
card/tmpsets/set/mod019-card-mod-carrierwave/type/image.rb 71.67 % 110 60 43 17 9.90
card/tmpsets/set/mod019-card-mod-carrierwave/type/image/html_views.rb 56.41 % 78 39 22 17 1.41
card/tmpsets/set/mod020-card-mod-date/all/calendar.rb 100.00 % 18 8 8 0 1.38
card/tmpsets/set/mod020-card-mod-date/self/datepicker.rb 83.33 % 15 6 5 1 1.17
card/tmpsets/set/mod020-card-mod-date/self/script_datepicker.rb 87.50 % 16 8 7 1 1.13
card/tmpsets/set/mod020-card-mod-date/self/script_datepicker_config.rb 100.00 % 13 7 7 0 1.29
card/tmpsets/set/mod020-card-mod-date/self/style_datepicker.rb 100.00 % 20 10 10 0 1.60
card/tmpsets/set/mod020-card-mod-date/type/date.rb 100.00 % 14 7 7 0 1.43
card/tmpsets/set/mod022-card-mod-follow/abstract/follow_option.rb 93.10 % 65 29 27 2 2.10
card/tmpsets/set/mod022-card-mod-follow/all/follow.rb 65.00 % 42 20 13 7 1.40
card/tmpsets/set/mod022-card-mod-follow/all/follow/follow_link.rb 50.00 % 69 30 15 15 0.57
card/tmpsets/set/mod022-card-mod-follow/all/follow/follow_link_views.rb 73.68 % 38 19 14 5 1.05
card/tmpsets/set/mod022-card-mod-follow/all/follow/followed_by.rb 71.05 % 79 38 27 11 33.11
card/tmpsets/set/mod022-card-mod-follow/all/follow/follower_ids.rb 62.32 % 130 69 43 26 16.64
card/tmpsets/set/mod022-card-mod-follow/all/follow/start_follow_link.rb 50.00 % 19 10 5 5 0.70
card/tmpsets/set/mod022-card-mod-follow/all/follow/stop_follow_link.rb 45.45 % 20 11 5 6 0.64
card/tmpsets/set/mod022-card-mod-follow/all/notify.rb 90.91 % 90 44 40 4 39.52
card/tmpsets/set/mod022-card-mod-follow/all/notify/base_views.rb 80.28 % 136 71 57 14 3.35
card/tmpsets/set/mod022-card-mod-follow/all/notify/html_views.rb 81.82 % 26 11 9 2 1.45
card/tmpsets/set/mod022-card-mod-follow/right/account.rb 54.55 % 24 11 6 5 0.73
card/tmpsets/set/mod022-card-mod-follow/right/follow.rb 43.33 % 127 60 26 34 0.48
card/tmpsets/set/mod022-card-mod-follow/right/follow_fields.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod022-card-mod-follow/right/followers.rb 71.43 % 32 14 10 4 0.93
card/tmpsets/set/mod022-card-mod-follow/right/following.rb 43.33 % 59 30 13 17 0.53
card/tmpsets/set/mod022-card-mod-follow/self/always.rb 81.82 % 22 11 9 2 1.00
card/tmpsets/set/mod022-card-mod-follow/self/created.rb 78.57 % 28 14 11 3 5.29
card/tmpsets/set/mod022-card-mod-follow/self/edited.rb 78.57 % 29 14 11 3 5.29
card/tmpsets/set/mod022-card-mod-follow/self/follow.rb 100.00 % 11 6 6 0 1.33
card/tmpsets/set/mod022-card-mod-follow/self/follow_defaults.rb 35.90 % 97 39 14 25 0.44
card/tmpsets/set/mod022-card-mod-follow/self/never.rb 81.82 % 22 11 9 2 1.00
card/tmpsets/set/mod022-card-mod-follow/type/cardtype.rb 66.67 % 30 15 10 5 0.87
card/tmpsets/set/mod022-card-mod-follow/type/set.rb 61.29 % 62 31 19 12 1.23
card/tmpsets/set/mod022-card-mod-follow/type/user.rb 55.56 % 16 9 5 4 0.78
card/tmpsets/set/mod022-card-mod-follow/type_plus_right/user/follow.rb 45.24 % 86 42 19 23 0.55
card/tmpsets/set/mod022-card-mod-follow/type_plus_right/user/follow/follow_editor_helper.rb 31.67 % 130 60 19 41 0.40
card/tmpsets/set/mod023-card-mod-google_analytics/all/google_analytics.rb 83.33 % 51 24 20 4 6.25
card/tmpsets/set/mod024-card-mod-markdown/type/markdown.rb 84.62 % 26 13 11 2 2.46
card/tmpsets/set/mod025-card-mod-prosemirror_editor/all/prosemirror_editor.rb 75.00 % 17 8 6 2 1.13
card/tmpsets/set/mod025-card-mod-prosemirror_editor/self/script_prosemirror.rb 100.00 % 13 7 7 0 1.29
card/tmpsets/set/mod025-card-mod-prosemirror_editor/self/script_prosemirror_config.rb 100.00 % 14 7 7 0 1.29
card/tmpsets/set/mod025-card-mod-prosemirror_editor/self/style_prosemirror.rb 100.00 % 12 6 6 0 1.33
card/tmpsets/set/mod026-card-mod-recaptcha/all/recaptcha.rb 62.00 % 111 50 31 19 16.96
card/tmpsets/set/mod026-card-mod-recaptcha/self/admin_info.rb 56.25 % 41 16 9 7 0.75
card/tmpsets/set/mod026-card-mod-recaptcha/self/recaptcha_proxy.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod026-card-mod-recaptcha/self/recaptcha_secret_key.rb 66.67 % 18 9 6 3 0.89
card/tmpsets/set/mod026-card-mod-recaptcha/self/recaptcha_settings.rb 85.71 % 53 7 6 1 1.29
card/tmpsets/set/mod026-card-mod-recaptcha/self/recaptcha_site_key.rb 66.67 % 18 9 6 3 0.89
card/tmpsets/set/mod027-card-mod-rules/right/self.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod027-card-mod-rules/rstar/rule_user.rb 75.00 % 17 8 6 2 1.00
card/tmpsets/set/mod027-card-mod-rules/rule/bar_view.rb 46.94 % 101 49 23 26 0.53
card/tmpsets/set/mod027-card-mod-rules/rule/bridge_rules_editor.rb 55.56 % 37 18 10 8 0.72
card/tmpsets/set/mod027-card-mod-rules/rule/editor.rb 42.59 % 119 54 23 31 0.48
card/tmpsets/set/mod027-card-mod-rules/rule/html_views.rb 88.89 % 22 9 8 1 3.22
card/tmpsets/set/mod027-card-mod-rules/rule/quick_editor.rb 57.14 % 48 21 12 9 0.71
card/tmpsets/set/mod027-card-mod-rules/rule/rule_form.rb 37.14 % 66 35 13 22 0.46
card/tmpsets/set/mod027-card-mod-rules/rule/rule_form/buttons.rb 43.48 % 55 23 10 13 0.61
card/tmpsets/set/mod027-card-mod-rules/rule/rule_form/form_elements.rb 33.33 % 61 33 11 22 0.45
card/tmpsets/set/mod027-card-mod-rules/rule/rule_form/rule_set_radio.rb 36.17 % 91 47 17 30 0.40
card/tmpsets/set/mod027-card-mod-rules/rule/rule_form/set_selection.rb 39.13 % 48 23 9 14 0.57
card/tmpsets/set/mod027-card-mod-rules/rule/rules.rb 47.46 % 118 59 28 31 1.07
card/tmpsets/set/mod027-card-mod-rules/self/script_rules.rb 100.00 % 12 6 6 0 1.33
card/tmpsets/set/mod027-card-mod-rules/type/set.rb 51.61 % 116 62 32 30 8.10
card/tmpsets/set/mod027-card-mod-rules/type/set/html_views.rb 58.62 % 60 29 17 12 0.93
card/tmpsets/set/mod027-card-mod-rules/type/set/html_views/rule_lists.rb 50.00 % 51 26 13 13 0.69
card/tmpsets/set/mod027-card-mod-rules/type/set/html_views/template.rb 63.64 % 21 11 7 4 1.09
card/tmpsets/set/mod027-card-mod-rules/type/set/rules_filter.rb 46.43 % 69 28 13 15 0.61
card/tmpsets/set/mod027-card-mod-rules/type/set/setting_lists.rb 48.78 % 85 41 20 21 0.59
card/tmpsets/set/mod028-card-mod-tinymce_editor/all/reference_editor.rb 52.38 % 41 21 11 10 0.67
card/tmpsets/set/mod028-card-mod-tinymce_editor/all/reference_editor/link_editor.rb 57.89 % 42 19 11 8 0.79
card/tmpsets/set/mod028-card-mod-tinymce_editor/all/reference_editor/link_editor/link_parser.rb 52.38 % 43 21 11 10 0.67
card/tmpsets/set/mod028-card-mod-tinymce_editor/all/reference_editor/nest_editor.rb 33.33 % 185 87 29 58 0.38
card/tmpsets/set/mod028-card-mod-tinymce_editor/all/reference_editor/nest_image.rb 41.67 % 79 36 15 21 0.56
card/tmpsets/set/mod028-card-mod-tinymce_editor/all/tinymce_editor.rb 100.00 % 16 7 7 0 2.29
card/tmpsets/set/mod028-card-mod-tinymce_editor/self/script_tinymce.rb 100.00 % 13 7 7 0 1.29
card/tmpsets/set/mod028-card-mod-tinymce_editor/self/script_tinymce_config.rb 100.00 % 13 7 7 0 1.29
card/tmpsets/set/mod028-card-mod-tinymce_editor/self/tiny_mce.rb 83.33 % 16 6 5 1 1.17
card/tmpsets/set/mod030-card-mod-monkey/all/event_viz.rb 33.33 % 73 36 12 24 0.39
card/tmpsets/set/mod030-card-mod-monkey/all/view_viz.rb 38.89 % 32 18 7 11 0.56
card/tmpsets/set/mod030-card-mod-monkey/right/debug.rb 30.61 % 97 49 15 34 0.37
card/tmpsets/set_pattern/100-all.rb 81.82 % 23 11 9 2 13.45
card/tmpsets/set_pattern/101-all_plus.rb 75.00 % 25 12 9 3 0.75
card/tmpsets/set_pattern/102-type.rb 85.00 % 41 20 17 3 690.90
card/tmpsets/set_pattern/103-star.rb 76.92 % 27 13 10 3 380.69
card/tmpsets/set_pattern/104-rstar.rb 85.71 % 29 14 12 2 353.64
card/tmpsets/set_pattern/105-rule.rb 85.71 % 29 14 12 2 354.36
card/tmpsets/set_pattern/106-right.rb 81.25 % 36 16 13 3 108.00
card/tmpsets/set_pattern/107-type_plus_right.rb 77.78 % 44 18 14 4 93.11
card/tmpsets/set_pattern/108-self.rb 88.24 % 35 17 15 2 588.06
decko/lib/decko/response.rb 90.91 % 170 88 80 8 7.39
decko/rails/controllers/application_controller.rb 100.00 % 2 1 1 0 1.00
decko/rails/controllers/card_controller.rb 98.72 % 151 78 77 1 11.50

Card ( 89.89% covered at 1831.89 hits/line )

95 files in total.
3650 relevant lines, 3281 lines covered and 369 lines missed. ( 89.89% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
card-mod-bootstrap/lib/card/lazy_tab.rb 95.00 % 37 20 19 1 29.40
card-mod-bootstrap/lib/card/tab.rb 100.00 % 76 40 40 0 67.73
card-mod-follow/lib/card/follower_stash.rb 97.83 % 88 46 45 1 35.52
card-mod-history/lib/card/act.rb 93.18 % 137 44 41 3 163.57
card-mod-history/lib/card/act/act_renderer.rb 89.89 % 217 89 80 9 3.83
card-mod-history/lib/card/act/act_renderer/absolute_act_renderer.rb 100.00 % 34 13 13 0 1.00
card-mod-history/lib/card/act/act_renderer/bridge_act_renderer.rb 66.67 % 53 27 18 9 0.67
card-mod-history/lib/card/act/act_renderer/relative_act_renderer.rb 80.77 % 59 26 21 5 1.19
card-mod-history/lib/card/action.rb 96.20 % 230 79 76 3 429.80
card-mod-history/lib/card/action/action_renderer.rb 93.62 % 94 47 44 3 3.40
card-mod-history/lib/card/action/admin.rb 57.89 % 36 19 11 8 0.58
card-mod-history/lib/card/action/differ.rb 90.00 % 89 40 36 4 12.53
card-mod-history/lib/card/change.rb 94.44 % 70 18 17 1 236.22
card-mod-machines/lib/card/machine.rb 57.89 % 33 19 11 8 6.26
card-mod-tinymce_editor/lib/card/reference/nest_parser.rb 97.44 % 74 39 38 1 13.05
card-mod-virtual/lib/card/virtual.rb 88.46 % 95 52 46 6 107.12
card/lib/card/auth.rb 88.89 % 45 18 16 2 4.06
card/lib/card/auth/current.rb 91.78 % 158 73 67 6 978.62
card/lib/card/auth/permissions.rb 96.88 % 72 32 31 1 3620.63
card/lib/card/auth/proxy.rb 100.00 % 59 27 27 0 5554.30
card/lib/card/auth/setup.rb 71.43 % 55 28 20 8 3.32
card/lib/card/auth/token.rb 84.21 % 38 19 16 3 8.47
card/lib/card/cache/persistent.rb 76.56 % 154 64 49 15 5.94
card/lib/card/content.rb 86.11 % 153 72 62 10 1075.51
card/lib/card/content/chunk.rb 95.65 % 96 46 44 2 784.98
card/lib/card/content/chunk/abstract.rb 95.24 % 88 42 40 2 1818.88
card/lib/card/content/clean.rb 100.00 % 95 50 50 0 344.08
card/lib/card/content/diff.rb 100.00 % 70 33 33 0 13.94
card/lib/card/content/diff/l_c_s.rb 97.96 % 90 49 48 1 31.90
card/lib/card/content/diff/l_c_s/processor.rb 93.55 % 163 93 87 6 22.62
card/lib/card/content/diff/result.rb 91.49 % 159 94 86 8 12.19
card/lib/card/content/parser.rb 100.00 % 104 49 49 0 3959.45
card/lib/card/content/truncate.rb 26.32 % 67 38 10 28 0.26
card/lib/card/director/subdirector_array.rb 100.00 % 51 29 29 0 1022.45
card/lib/card/env/success.rb 90.22 % 171 92 83 9 41.79
card/lib/card/error.rb 92.94 % 173 85 79 6 7.14
card/lib/card/format/nest.rb 100.00 % 81 39 39 0 4474.59
card/lib/card/format/nest/fetch.rb 100.00 % 75 41 41 0 840.78
card/lib/card/mailer.rb 100.00 % 38 18 18 0 40.33
card/lib/card/migration.rb 37.04 % 159 81 30 51 0.67
card/lib/card/migration/core.rb 100.00 % 11 5 5 0 1.00
card/lib/card/migration/import.rb 71.43 % 119 49 35 14 2.22
card/lib/card/migration/import/import_data.rb 84.62 % 118 65 55 10 4.80
card/lib/card/migration/import/import_data/card_attributes.rb 88.57 % 64 35 31 4 8.37
card/lib/card/migration/import/import_data/card_content.rb 93.75 % 30 16 15 1 3.06
card/lib/card/migration/import/merger.rb 100.00 % 36 20 20 0 1.00
card/lib/card/mod/load_strategy/eval.rb 100.00 % 16 8 8 0 65.38
card/lib/card/query.rb 100.00 % 110 23 23 0 1221.35
card/lib/card/query/abstract_query.rb 100.00 % 95 48 48 0 4664.60
card/lib/card/query/abstract_query/query_helper.rb 100.00 % 56 30 30 0 5402.63
card/lib/card/query/abstract_query/tie.rb 100.00 % 104 52 52 0 2109.19
card/lib/card/query/act_query.rb 100.00 % 26 13 13 0 66.31
card/lib/card/query/action_query.rb 100.00 % 36 19 19 0 48.32
card/lib/card/query/card_query.rb 100.00 % 59 30 30 0 1432.70
card/lib/card/query/card_query/conjunctions.rb 100.00 % 48 26 26 0 328.15
card/lib/card/query/card_query/found_by.rb 95.24 % 43 21 20 1 11.71
card/lib/card/query/card_query/interpretation.rb 95.92 % 100 49 47 2 3059.51
card/lib/card/query/card_query/match_attributes.rb 100.00 % 44 20 20 0 6.25
card/lib/card/query/card_query/normalization.rb 90.91 % 60 33 30 3 3534.88
card/lib/card/query/card_query/reference_attributes.rb 100.00 % 45 15 15 0 169.40
card/lib/card/query/card_query/relational_attributes.rb 100.00 % 95 45 45 0 90.58
card/lib/card/query/card_query/run.rb 90.00 % 112 60 54 6 3255.65
card/lib/card/query/card_query/sorting.rb 97.96 % 101 49 48 1 1.10
card/lib/card/query/clause.rb 100.00 % 19 9 9 0 1816.78
card/lib/card/query/join.rb 84.00 % 126 50 42 8 3334.66
card/lib/card/query/reference_query.rb 93.33 % 54 30 28 2 1257.97
card/lib/card/query/sql_statement.rb 98.48 % 120 66 65 1 2280.77
card/lib/card/query/sql_statement/joins.rb 100.00 % 62 37 37 0 2649.92
card/lib/card/query/sql_statement/order.rb 100.00 % 68 30 30 0 2185.10
card/lib/card/query/sql_statement/where.rb 100.00 % 102 54 54 0 3257.19
card/lib/card/query/value.rb 94.34 % 94 53 50 3 1755.40
card/lib/card/query/value/match_value.rb 96.77 % 65 31 30 1 21.03
card/lib/card/reference.rb 58.82 % 85 34 20 14 427.44
card/lib/card/seed_consts.rb 87.50 % 20 8 7 1 0.88
card/lib/card/set/type.rb 100.00 % 46 26 26 0 898.69
card/lib/card/subcards.rb 91.07 % 114 56 51 5 1964.20
card/lib/card/subcards/add.rb 88.33 % 120 60 53 7 519.82
card/lib/card/subcards/relate.rb 92.86 % 27 14 13 1 22.07
card/lib/card/subcards/remove.rb 66.67 % 44 27 18 9 0.67
card/lib/card/version.rb 100.00 % 11 5 5 0 7.00
card/lib/card/view.rb 93.18 % 119 44 41 3 12225.00
card/lib/card/view/cache.rb 89.29 % 298 56 50 6 722.20
card/lib/card/view/cache/cache_action.rb 72.73 % 121 44 32 12 3668.27
card/lib/card/view/cache/stub.rb 60.00 % 46 15 9 6 0.60
card/lib/card/view/classy.rb 78.26 % 168 69 54 15 5675.77
card/lib/card/view/options.rb 100.00 % 93 15 15 0 1.00
card/lib/card/view/options/key_lists.rb 100.00 % 45 18 18 0 3945.72
card/lib/card/view/options/visibility.rb 93.18 % 99 44 41 3 11089.23
card/lib/card/view/options/voo_api.rb 94.44 % 204 90 85 5 17850.03
card/lib/card/view/permission.rb 100.00 % 54 25 25 0 11959.56
card/mod/core/lib/card/rule/preference_cache.rb 100.00 % 74 30 30 0 274.57
card/mod/core/lib/card/rule/read_rule_cache.rb 100.00 % 30 11 11 0 453.45
card/mod/standard/lib/card/layout/card_layout.rb 95.65 % 44 23 22 1 6.96
card/mod/standard/lib/card/layout/code_layout.rb 80.00 % 9 5 4 1 0.80
card/mod/standard/lib/card/layout/unknown_layout.rb 70.00 % 20 10 7 3 0.70

Set Patterns ( 82.22% covered at 312.87 hits/line )

9 files in total.
135 relevant lines, 111 lines covered and 24 lines missed. ( 82.22% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
card/tmpsets/set_pattern/100-all.rb 81.82 % 23 11 9 2 13.45
card/tmpsets/set_pattern/101-all_plus.rb 75.00 % 25 12 9 3 0.75
card/tmpsets/set_pattern/102-type.rb 85.00 % 41 20 17 3 690.90
card/tmpsets/set_pattern/103-star.rb 76.92 % 27 13 10 3 380.69
card/tmpsets/set_pattern/104-rstar.rb 85.71 % 29 14 12 2 353.64
card/tmpsets/set_pattern/105-rule.rb 85.71 % 29 14 12 2 354.36
card/tmpsets/set_pattern/106-right.rb 81.25 % 36 16 13 3 108.00
card/tmpsets/set_pattern/107-type_plus_right.rb 77.78 % 44 18 14 4 93.11
card/tmpsets/set_pattern/108-self.rb 88.24 % 35 17 15 2 588.06

Sets ( 66.4% covered at 170.37 hits/line )

429 files in total.
11683 relevant lines, 7757 lines covered and 3926 lines missed. ( 66.4% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
card/tmpsets/set/mod001-utility/abstract/bs_badge.rb 56.25 % 31 16 9 7 0.75
card/tmpsets/set/mod001-utility/abstract/filterable.rb 53.85 % 22 13 7 6 0.77
card/tmpsets/set/mod001-utility/abstract/filterable_bar.rb 63.64 % 20 11 7 4 0.82
card/tmpsets/set/mod001-utility/abstract/utility.rb 60.00 % 22 10 6 4 0.80
card/tmpsets/set/mod002-admin/self/admin.rb 28.77 % 152 73 21 52 0.33
card/tmpsets/set/mod002-admin/self/admin_info.rb 52.00 % 57 25 13 12 0.64
card/tmpsets/set/mod002-admin/self/debugger.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod002-admin/self/trash.rb 48.00 % 72 25 12 13 0.60
card/tmpsets/set/mod002-admin/self/version.rb 100.00 % 22 8 8 0 6.75
card/tmpsets/set/mod003-core/abstract/code_file.rb 78.00 % 93 50 39 11 6.82
card/tmpsets/set/mod003-core/abstract/haml_file.rb 58.82 % 33 17 10 7 0.76
card/tmpsets/set/mod003-core/abstract/lock.rb 100.00 % 35 19 19 0 1.32
card/tmpsets/set/mod003-core/abstract/vendor_code_file.rb 90.00 % 19 10 9 1 1.10
card/tmpsets/set/mod003-core/all/abort.rb 75.00 % 85 44 33 11 114.50
card/tmpsets/set/mod003-core/all/actify.rb 100.00 % 77 43 43 0 164.56
card/tmpsets/set/mod003-core/all/active_card.rb 100.00 % 15 7 7 0 21.29
card/tmpsets/set/mod003-core/all/assign_attributes.rb 98.73 % 135 79 78 1 1954.10
card/tmpsets/set/mod003-core/all/cache.rb 82.09 % 118 67 55 12 2584.51
card/tmpsets/set/mod003-core/all/chunk.rb 37.35 % 151 83 31 52 0.64
card/tmpsets/set/mod003-core/all/codename.rb 66.67 % 38 21 14 7 59.05
card/tmpsets/set/mod003-core/all/collection.rb 66.67 % 64 33 22 11 44.12
card/tmpsets/set/mod003-core/all/content.rb 75.00 % 187 92 69 23 120.36
card/tmpsets/set/mod003-core/all/contextual_content.rb 100.00 % 37 20 20 0 147.60
card/tmpsets/set/mod003-core/all/debug.rb 100.00 % 32 19 19 0 7.05
card/tmpsets/set/mod003-core/all/event_conditions.rb 79.35 % 181 92 73 19 5801.55
card/tmpsets/set/mod003-core/all/export.rb 40.00 % 77 40 16 24 0.48
card/tmpsets/set/mod003-core/all/extended.rb 92.00 % 58 25 23 2 10.56
card/tmpsets/set/mod003-core/all/fetch.rb 79.59 % 131 49 39 10 3332.22
card/tmpsets/set/mod003-core/all/fetch_helper.rb 100.00 % 44 22 22 0 18.09
card/tmpsets/set/mod003-core/all/haml.rb 75.86 % 84 29 22 7 28.72
card/tmpsets/set/mod003-core/all/i18n.rb 100.00 % 19 9 9 0 6.44
card/tmpsets/set/mod003-core/all/initialize.rb 100.00 % 85 49 49 0 2564.63
card/tmpsets/set/mod003-core/all/item.rb 45.45 % 139 77 35 42 6.06
card/tmpsets/set/mod003-core/all/layouts.rb 64.71 % 43 17 11 6 0.82
card/tmpsets/set/mod003-core/all/location_history.rb 100.00 % 28 14 14 0 16.93
card/tmpsets/set/mod003-core/all/name.rb 90.23 % 248 133 120 13 1839.16
card/tmpsets/set/mod003-core/all/name_events.rb 80.26 % 143 76 61 15 66.00
card/tmpsets/set/mod003-core/all/observer.rb 93.75 % 31 16 15 1 108.44
card/tmpsets/set/mod003-core/all/pattern.rb 93.94 % 63 33 31 2 3408.73
card/tmpsets/set/mod003-core/all/permissions.rb 88.80 % 242 125 111 14 263.35
card/tmpsets/set/mod003-core/all/references.rb 93.55 % 200 93 87 6 85.77
card/tmpsets/set/mod003-core/all/rename.rb 96.30 % 42 27 26 1 10.41
card/tmpsets/set/mod003-core/all/rules.rb 78.26 % 90 46 36 10 2428.00
card/tmpsets/set/mod003-core/all/states.rb 80.00 % 93 35 28 7 2583.60
card/tmpsets/set/mod003-core/all/subcards.rb 73.13 % 128 67 49 18 170.27
card/tmpsets/set/mod003-core/all/tabs.rb 40.00 % 60 30 12 18 0.50
card/tmpsets/set/mod003-core/all/templating.rb 92.50 % 80 40 37 3 732.60
card/tmpsets/set/mod003-core/all/trash.rb 63.77 % 136 69 44 25 23.62
card/tmpsets/set/mod003-core/all/type.rb 88.24 % 70 34 30 4 706.56
card/tmpsets/set/mod003-core/all/update_read_rules.rb 100.00 % 21 9 9 0 72.67
card/tmpsets/set/mod003-core/all/utils.rb 35.19 % 101 54 19 35 1.70
card/tmpsets/set/mod004-card-mod-format/all/all_css.rb 54.17 % 46 24 13 11 0.67
card/tmpsets/set/mod004-card-mod-format/all/all_csv.rb 38.89 % 102 54 21 33 0.44
card/tmpsets/set/mod004-card-mod-format/all/all_js.rb 77.78 % 19 9 7 2 1.11
card/tmpsets/set/mod004-card-mod-format/all/base.rb 76.39 % 146 72 55 17 19.47
card/tmpsets/set/mod004-card-mod-format/all/file.rb 77.78 % 18 9 7 2 1.11
card/tmpsets/set/mod004-card-mod-format/all/head.rb 93.42 % 157 76 71 5 24.92
card/tmpsets/set/mod004-card-mod-format/all/json.rb 41.10 % 164 73 30 43 0.45
card/tmpsets/set/mod004-card-mod-format/all/rss.rb 45.83 % 85 48 22 26 0.52
card/tmpsets/set/mod004-card-mod-format/all/text.rb 100.00 % 16 7 7 0 1.86
card/tmpsets/set/mod004-card-mod-format/self/head.rb 91.67 % 31 12 11 1 6.67
card/tmpsets/set/mod004-card-mod-format/type/html.rb 72.22 % 36 18 13 5 7.28
card/tmpsets/set/mod004-card-mod-format/type/json.rb 70.83 % 50 24 17 7 1.96
card/tmpsets/set/mod004-card-mod-format/type/plain_text.rb 77.78 % 18 9 7 2 1.11
card/tmpsets/set/mod005-pointer/abstract/00_paging_params.rb 85.00 % 40 20 17 3 1.15
card/tmpsets/set/mod005-pointer/abstract/01_paging.rb 41.89 % 156 74 31 43 0.49
card/tmpsets/set/mod005-pointer/abstract/01_paging/paging_links.rb 41.86 % 98 43 18 25 0.47
card/tmpsets/set/mod005-pointer/abstract/02_items.rb 78.16 % 207 87 68 19 418.05
card/tmpsets/set/mod005-pointer/abstract/02_pointer.rb 80.00 % 19 10 8 2 1.00
card/tmpsets/set/mod005-pointer/abstract/02_pointer/events.rb 57.89 % 80 38 22 16 6.03
card/tmpsets/set/mod005-pointer/abstract/02_pointer/html_views.rb 49.18 % 134 61 30 31 0.80
card/tmpsets/set/mod005-pointer/abstract/02_pointer/html_views/filter.rb 46.88 % 71 32 15 17 0.66
card/tmpsets/set/mod005-pointer/abstract/02_pointer/options_api.rb 48.84 % 87 43 21 22 1.05
card/tmpsets/set/mod005-pointer/abstract/02_pointer/other_views.rb 56.00 % 111 50 28 22 0.74
card/tmpsets/set/mod005-pointer/abstract/code_pointer.rb 85.00 % 44 20 17 3 5.75
card/tmpsets/set/mod005-pointer/abstract/id_pointer.rb 50.00 % 30 14 7 7 0.64
card/tmpsets/set/mod005-pointer/right/content_options.rb 71.43 % 13 7 5 2 1.00
card/tmpsets/set/mod005-pointer/self/input_options.rb 92.86 % 22 14 13 1 1.07
card/tmpsets/set/mod005-pointer/self/script_editors.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod005-pointer/self/script_libraries.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod005-pointer/self/script_mods.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod005-pointer/self/script_pointer_config.rb 88.89 % 18 9 8 1 1.11
card/tmpsets/set/mod005-pointer/self/style_libraries.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod005-pointer/self/style_mods.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod005-pointer/type/link_list.rb 53.85 % 49 26 14 12 0.69
card/tmpsets/set/mod005-pointer/type/list.rb 76.92 % 25 13 10 3 13.54
card/tmpsets/set/mod005-pointer/type/mirror_list.rb 36.73 % 102 49 18 31 0.41
card/tmpsets/set/mod005-pointer/type/mirrored_list.rb 31.75 % 121 63 20 43 0.35
card/tmpsets/set/mod005-pointer/type/nest_list.rb 53.33 % 55 30 16 14 0.67
card/tmpsets/set/mod005-pointer/type/pointer.rb 70.00 % 19 10 7 3 1.00
card/tmpsets/set/mod006-card-mod-virtual/abstract/virtual_cache.rb 79.17 % 52 24 19 5 0.96
card/tmpsets/set/mod007-card-mod-machines/abstract/machine.rb 84.68 % 230 111 94 17 3.23
card/tmpsets/set/mod007-card-mod-machines/abstract/machine/output_cache.rb 100.00 % 25 12 12 0 1.42
card/tmpsets/set/mod007-card-mod-machines/abstract/machine/output_update.rb 82.98 % 77 47 39 8 4.96
card/tmpsets/set/mod007-card-mod-machines/abstract/machine_input.rb 68.29 % 81 41 28 13 1.68
card/tmpsets/set/mod007-card-mod-machines/abstract/script.rb 56.82 % 93 44 25 19 0.75
card/tmpsets/set/mod007-card-mod-machines/abstract/skin_box.rb 52.38 % 42 21 11 10 0.71
card/tmpsets/set/mod007-card-mod-machines/all/reset_machines.rb 38.89 % 31 18 7 11 0.50
card/tmpsets/set/mod007-card-mod-machines/right/machine_cache.rb 85.71 % 14 7 6 1 1.14
card/tmpsets/set/mod007-card-mod-machines/right/machine_input.rb 100.00 % 16 8 8 0 1.75
card/tmpsets/set/mod007-card-mod-machines/right/machine_output.rb 88.89 % 53 27 24 3 1.19
card/tmpsets/set/mod007-card-mod-machines/self/script_decko.rb 75.00 % 21 8 6 2 1.00
card/tmpsets/set/mod007-card-mod-machines/self/script_html5shiv_printshiv.rb 100.00 % 20 8 8 0 4.13
card/tmpsets/set/mod007-card-mod-machines/self/script_jquery.rb 77.78 % 19 9 7 2 1.00
card/tmpsets/set/mod007-card-mod-machines/self/script_jquery_helper.rb 87.50 % 23 8 7 1 1.13
card/tmpsets/set/mod007-card-mod-machines/self/style_bootstrap_compatible.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod007-card-mod-machines/self/style_cards.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod007-card-mod-machines/self/style_jquery_ui_smoothness.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod007-card-mod-machines/type/coffee_script.rb 64.71 % 34 17 11 6 0.88
card/tmpsets/set/mod007-card-mod-machines/type/css.rb 69.05 % 94 42 29 13 0.81
card/tmpsets/set/mod007-card-mod-machines/type/java_script.rb 87.50 % 18 8 7 1 1.25
card/tmpsets/set/mod007-card-mod-machines/type/scss.rb 85.71 % 30 14 12 2 1.14
card/tmpsets/set/mod007-card-mod-machines/type/skin.rb 88.89 % 18 9 8 1 1.11
card/tmpsets/set/mod008-settings/abstract/permission.rb 37.93 % 131 58 22 36 22.90
card/tmpsets/set/mod008-settings/abstract/templated_nests.rb 75.00 % 16 8 6 2 1.13
card/tmpsets/set/mod008-settings/all/supports_content_options.rb 75.00 % 16 8 6 2 1.00
card/tmpsets/set/mod008-settings/right/autoname.rb 100.00 % 12 6 6 0 1.50
card/tmpsets/set/mod008-settings/right/comment.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod008-settings/right/content_option_view.rb 66.67 % 19 9 6 3 1.00
card/tmpsets/set/mod008-settings/right/content_options.rb 61.54 % 27 13 8 5 0.85
card/tmpsets/set/mod008-settings/right/create.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod008-settings/right/default.rb 52.38 % 43 21 11 10 0.67
card/tmpsets/set/mod008-settings/right/delete.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod008-settings/right/guide.rb 85.71 % 17 7 6 1 1.29
card/tmpsets/set/mod008-settings/right/help.rb 72.73 % 24 11 8 3 1.00
card/tmpsets/set/mod008-settings/right/input_type.rb 60.00 % 44 20 12 8 0.75
card/tmpsets/set/mod008-settings/right/read.rb 97.73 % 88 44 43 1 2.09
card/tmpsets/set/mod008-settings/right/script.rb 84.62 % 28 13 11 2 1.08
card/tmpsets/set/mod008-settings/right/structure.rb 42.50 % 81 40 17 23 0.53
card/tmpsets/set/mod008-settings/right/style.rb 58.82 % 65 34 20 14 1.44
card/tmpsets/set/mod008-settings/right/update.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod008-settings/self/autoname.rb 100.00 % 13 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/captcha.rb 100.00 % 14 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/content_option_view.rb 85.71 % 19 7 6 1 1.14
card/tmpsets/set/mod008-settings/self/content_options.rb 85.71 % 19 7 6 1 1.14
card/tmpsets/set/mod008-settings/self/create.rb 100.00 % 13 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/csv_structure.rb 100.00 % 11 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/default.rb 100.00 % 12 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/default_html_view.rb 100.00 % 11 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/delete.rb 100.00 % 13 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/follow_fields.rb 100.00 % 11 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/guide.rb 100.00 % 12 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/head.rb 100.00 % 13 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/help.rb 100.00 % 14 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/input_type.rb 88.89 % 22 9 8 1 1.22
card/tmpsets/set/mod008-settings/self/layout.rb 100.00 % 13 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/on_create.rb 100.00 % 12 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/on_delete.rb 100.00 % 12 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/on_update.rb 100.00 % 12 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/read.rb 100.00 % 13 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/recent_settings.rb 87.50 % 16 8 7 1 4.75
card/tmpsets/set/mod008-settings/self/script.rb 100.00 % 11 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/structure.rb 100.00 % 14 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/style.rb 100.00 % 13 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/table_of_contents.rb 100.00 % 14 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/thanks.rb 100.00 % 14 6 6 0 1.33
card/tmpsets/set/mod008-settings/self/update.rb 100.00 % 13 6 6 0 1.33
card/tmpsets/set/mod008-settings/type/setting.rb 48.48 % 88 33 16 17 0.64
card/tmpsets/set/mod009-card-mod-search/abstract/00_filter_helper.rb 76.67 % 64 30 23 7 18.13
card/tmpsets/set/mod009-card-mod-search/abstract/02_search_params.rb 75.76 % 67 33 25 8 0.97
card/tmpsets/set/mod009-card-mod-search/abstract/03_filter.rb 75.00 % 32 16 12 4 1.06
card/tmpsets/set/mod009-card-mod-search/abstract/03_filter/filter_form.rb 44.44 % 107 45 20 25 0.53
card/tmpsets/set/mod009-card-mod-search/abstract/03_filter/form_helper.rb 35.94 % 114 64 23 41 0.42
card/tmpsets/set/mod009-card-mod-search/abstract/03_filter/query_construction.rb 68.18 % 45 22 15 7 10.91
card/tmpsets/set/mod009-card-mod-search/abstract/04_right_filter_form.rb 68.75 % 35 16 11 5 0.88
card/tmpsets/set/mod009-card-mod-search/abstract/05_search.rb 62.75 % 93 51 32 19 0.88
card/tmpsets/set/mod009-card-mod-search/abstract/05_search/views.rb 45.35 % 168 86 39 47 0.55
card/tmpsets/set/mod009-card-mod-search/abstract/06_cql_search.rb 88.89 % 117 63 56 7 135.22
card/tmpsets/set/mod009-card-mod-search/right/children.rb 83.33 % 13 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/created.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/edited.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/editors.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/follow.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/linked_to_by.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/links_to.rb 83.33 % 14 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/mates.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/nested_by.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/nests.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/referred_to_by.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/right/refers_to.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod009-card-mod-search/self/recent.rb 66.67 % 44 24 16 8 2.71
card/tmpsets/set/mod009-card-mod-search/self/search.rb 42.31 % 105 52 22 30 0.52
card/tmpsets/set/mod009-card-mod-search/type/search_type.rb 54.35 % 89 46 25 21 1.09
card/tmpsets/set/mod010-standard/all/comment.rb 44.44 % 89 45 20 25 7.67
card/tmpsets/set/mod010-standard/all/error.rb 59.09 % 85 44 26 18 0.68
card/tmpsets/set/mod010-standard/all/links.rb 91.55 % 158 71 65 6 85.52
card/tmpsets/set/mod010-standard/all/list_changes.rb 80.77 % 58 26 21 5 26.92
card/tmpsets/set/mod010-standard/all/path.rb 89.61 % 184 77 69 8 125.23
card/tmpsets/set/mod010-standard/all/rich_html.rb 100.00 % 13 6 6 0 1.50
card/tmpsets/set/mod010-standard/all/rich_html/alert.rb 100.00 % 32 17 17 0 6.53
card/tmpsets/set/mod010-standard/all/rich_html/content.rb 62.89 % 177 97 61 36 3.76
card/tmpsets/set/mod010-standard/all/rich_html/error.rb 84.69 % 204 98 83 15 2.09
card/tmpsets/set/mod010-standard/all/rich_html/frame.rb 96.97 % 62 33 32 1 11.15
card/tmpsets/set/mod010-standard/all/rich_html/header.rb 88.89 % 70 36 32 4 6.33
card/tmpsets/set/mod010-standard/all/rich_html/html_views/guide.rb 81.82 % 60 33 27 6 6.61
card/tmpsets/set/mod010-standard/all/rich_html/html_views/help.rb 77.42 % 58 31 24 7 5.16
card/tmpsets/set/mod010-standard/all/rich_html/html_views/info.rb 38.10 % 93 42 16 26 0.60
card/tmpsets/set/mod010-standard/all/rich_html/html_views/size.rb 61.54 % 26 13 8 5 1.00
card/tmpsets/set/mod010-standard/all/rich_html/menu.rb 78.57 % 138 70 55 15 2.94
card/tmpsets/set/mod010-standard/all/rich_html/modal.rb 73.85 % 128 65 48 17 1.02
card/tmpsets/set/mod010-standard/all/rich_html/overlay.rb 37.10 % 113 62 23 39 0.44
card/tmpsets/set/mod010-standard/all/rich_html/process_layout.rb 72.09 % 80 43 31 12 15.40
card/tmpsets/set/mod010-standard/all/rich_html/show.rb 84.00 % 54 25 21 4 7.72
card/tmpsets/set/mod010-standard/all/rich_html/title.rb 89.29 % 56 28 25 3 45.86
card/tmpsets/set/mod010-standard/all/rich_html/wrapper.rb 86.59 % 156 82 71 11 97.32
card/tmpsets/set/mod010-standard/right/discussion.rb 60.00 % 18 10 6 4 0.80
card/tmpsets/set/mod010-standard/right/head.rb 84.62 % 26 13 11 2 4.46
card/tmpsets/set/mod010-standard/right/type_plus_right.rb 83.33 % 13 6 5 1 1.17
card/tmpsets/set/mod010-standard/right/when_created.rb 71.43 % 15 7 5 2 1.00
card/tmpsets/set/mod010-standard/right/when_last_edited.rb 71.43 % 15 7 5 2 1.00
card/tmpsets/set/mod010-standard/self/alerts.rb 83.33 % 14 6 5 1 1.17
card/tmpsets/set/mod010-standard/self/cardtype.rb 52.63 % 51 19 10 9 3.05
card/tmpsets/set/mod010-standard/self/codenames.rb 100.00 % 10 4 4 0 1.50
card/tmpsets/set/mod010-standard/self/foot.rb 83.33 % 15 6 5 1 1.17
card/tmpsets/set/mod010-standard/self/home.rb 88.89 % 18 9 8 1 6.22
card/tmpsets/set/mod010-standard/self/now.rb 83.33 % 15 6 5 1 1.17
card/tmpsets/set/mod010-standard/self/sidebar.rb 83.33 % 14 6 5 1 1.17
card/tmpsets/set/mod010-standard/type/basic.rb 39.02 % 72 41 16 25 0.54
card/tmpsets/set/mod010-standard/type/cardtype.rb 70.27 % 136 74 52 22 0.81
card/tmpsets/set/mod010-standard/type/layout_type.rb 66.67 % 25 12 8 4 0.92
card/tmpsets/set/mod010-standard/type/notification_template.rb 60.87 % 42 23 14 9 0.74
card/tmpsets/set/mod010-standard/type/number.rb 53.33 % 31 15 8 7 0.73
card/tmpsets/set/mod010-standard/type/phrase.rb 85.71 % 14 7 6 1 1.29
card/tmpsets/set/mod010-standard/type/session.rb 69.44 % 70 36 25 11 9.67
card/tmpsets/set/mod010-standard/type/toggle.rb 54.17 % 47 24 13 11 0.67
card/tmpsets/set/mod010-standard/type/uri.rb 75.00 % 24 12 9 3 1.08
card/tmpsets/set/mod011-card-mod-email/abstract/email_field.rb 90.00 % 50 20 18 2 1.45
card/tmpsets/set/mod011-card-mod-email/abstract/test_context.rb 84.21 % 35 19 16 3 1.58
card/tmpsets/set/mod011-card-mod-email/all/email_html.rb 77.78 % 18 9 7 2 1.11
card/tmpsets/set/mod011-card-mod-email/all/email_text.rb 72.73 % 23 11 8 3 1.00
card/tmpsets/set/mod011-card-mod-email/right/bcc.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod011-card-mod-email/right/cc.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod011-card-mod-email/right/from.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod011-card-mod-email/right/html_message.rb 91.67 % 22 12 11 1 1.42
card/tmpsets/set/mod011-card-mod-email/right/subject.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod011-card-mod-email/right/text_message.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod011-card-mod-email/right/to.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod011-card-mod-email/type/email_template.rb 61.40 % 100 57 35 22 1.16
card/tmpsets/set/mod011-card-mod-email/type/email_template/email_config.rb 93.62 % 90 47 44 3 3.43
card/tmpsets/set/mod012-card-mod-account/abstract/account_field.rb 54.55 % 26 11 6 5 0.73
card/tmpsets/set/mod012-card-mod-account/abstract/accountable.rb 56.00 % 58 25 14 11 0.68
card/tmpsets/set/mod012-card-mod-account/all/account.rb 85.19 % 106 54 46 8 150.76
card/tmpsets/set/mod012-card-mod-account/right/account.rb 54.29 % 67 35 19 16 0.60
card/tmpsets/set/mod012-card-mod-account/right/account/events.rb 38.46 % 107 52 20 32 0.48
card/tmpsets/set/mod012-card-mod-account/right/account/views.rb 60.00 % 74 35 21 14 0.77
card/tmpsets/set/mod012-card-mod-account/right/api_key.rb 57.14 % 57 14 8 6 0.71
card/tmpsets/set/mod012-card-mod-account/right/email.rb 40.74 % 52 27 11 16 0.48
card/tmpsets/set/mod012-card-mod-account/right/password.rb 51.72 % 60 29 15 14 0.62
card/tmpsets/set/mod012-card-mod-account/right/roles.rb 36.84 % 36 19 7 12 0.47
card/tmpsets/set/mod012-card-mod-account/right/salt.rb 72.73 % 22 11 8 3 0.91
card/tmpsets/set/mod012-card-mod-account/right/status.rb 64.29 % 27 14 9 5 0.79
card/tmpsets/set/mod012-card-mod-account/self/signin.rb 34.45 % 235 119 41 78 0.37
card/tmpsets/set/mod012-card-mod-account/type/role.rb 60.00 % 30 15 9 6 0.80
card/tmpsets/set/mod012-card-mod-account/type/signup.rb 50.00 % 63 32 16 16 0.56
card/tmpsets/set/mod012-card-mod-account/type/signup/views.rb 41.82 % 102 55 23 32 0.51
card/tmpsets/set/mod012-card-mod-account/type/user.rb 50.00 % 77 36 18 18 0.58
card/tmpsets/set/mod012-card-mod-account/type_plus_right/user/email.rb 70.00 % 22 10 7 3 1.00
card/tmpsets/set/mod013-navbar/abstract/account_dropdown.rb 100.00 % 34 16 16 0 7.94
card/tmpsets/set/mod013-navbar/abstract/pointer/html_views.rb 100.00 % 14 7 7 0 4.71
card/tmpsets/set/mod013-navbar/all/navbar_links.rb 93.33 % 67 30 28 2 33.53
card/tmpsets/set/mod013-navbar/right/enabled_roles.rb 77.14 % 70 35 27 8 4.14
card/tmpsets/set/mod013-navbar/self/account_links.rb 85.71 % 108 49 42 7 12.37
card/tmpsets/set/mod013-navbar/self/dropdown_divider.rb 88.89 % 18 9 8 1 3.67
card/tmpsets/set/mod013-navbar/self/navbox.rb 100.00 % 45 18 18 0 9.72
card/tmpsets/set/mod013-navbar/type/html.rb 63.64 % 23 11 7 4 0.91
card/tmpsets/set/mod014-card-mod-edit/all/bridge.rb 73.53 % 73 34 25 9 0.82
card/tmpsets/set/mod014-card-mod-edit/all/bridge/bridge_pills.rb 38.71 % 56 31 12 19 0.52
card/tmpsets/set/mod014-card-mod-edit/all/bridge/follow_section.rb 47.62 % 46 21 10 11 0.67
card/tmpsets/set/mod014-card-mod-edit/all/bridge/related_section.rb 56.25 % 43 16 9 7 0.81
card/tmpsets/set/mod014-card-mod-edit/all/bridge/tab_views.rb 46.15 % 50 26 12 14 0.62
card/tmpsets/set/mod014-card-mod-edit/all/bridge/tab_visibility.rb 78.13 % 62 32 25 7 1.09
card/tmpsets/set/mod014-card-mod-edit/all/edit_content.rb 39.29 % 69 28 11 17 0.50
card/tmpsets/set/mod014-card-mod-edit/all/edit_inline.rb 57.14 % 65 28 16 12 2.25
card/tmpsets/set/mod014-card-mod-edit/all/edit_name.rb 45.16 % 67 31 14 17 0.55
card/tmpsets/set/mod014-card-mod-edit/all/edit_type.rb 74.07 % 110 54 40 14 16.46
card/tmpsets/set/mod014-card-mod-edit/all/editing.rb 46.88 % 100 32 15 17 0.56
card/tmpsets/set/mod014-card-mod-edit/all/editor.rb 83.33 % 65 30 25 5 4.10
card/tmpsets/set/mod014-card-mod-edit/all/form.rb 79.34 % 254 121 96 25 8.29
card/tmpsets/set/mod014-card-mod-edit/all/form_buttons.rb 42.86 % 73 42 18 24 0.83
card/tmpsets/set/mod014-card-mod-edit/all/form_elements.rb 90.48 % 80 42 38 4 12.55
card/tmpsets/set/mod014-card-mod-edit/all/formgroup.rb 88.89 % 46 27 24 3 9.81
card/tmpsets/set/mod014-card-mod-edit/all/new.rb 79.79 % 197 94 75 19 3.57
card/tmpsets/set/mod014-card-mod-edit/all/overlay_guide.rb 100.00 % 18 6 6 0 1.67
card/tmpsets/set/mod014-card-mod-edit/all/template_nest.rb 33.33 % 51 27 9 18 0.44
card/tmpsets/set/mod014-card-mod-edit/type/list.rb 66.67 % 24 12 8 4 0.83
card/tmpsets/set/mod014-card-mod-edit/type/plain_text.rb 72.73 % 22 11 8 3 1.00
card/tmpsets/set/mod014-card-mod-edit/type/pointer.rb 70.00 % 20 10 7 3 0.90
card/tmpsets/set/mod015-card-mod-ace_editor/all/ace_editor.rb 77.78 % 21 9 7 2 1.11
card/tmpsets/set/mod015-card-mod-ace_editor/self/ace.rb 85.71 % 16 7 6 1 1.29
card/tmpsets/set/mod015-card-mod-ace_editor/self/script_ace.rb 100.00 % 13 7 7 0 1.29
card/tmpsets/set/mod015-card-mod-ace_editor/self/script_ace_config.rb 100.00 % 13 7 7 0 1.29
card/tmpsets/set/mod016-card-mod-bar_and_box/abstract/media.rb 64.29 % 26 14 9 5 0.86
card/tmpsets/set/mod016-card-mod-bar_and_box/all/bar.rb 81.67 % 114 60 49 11 9.05
card/tmpsets/set/mod016-card-mod-bar_and_box/all/box.rb 66.67 % 25 12 8 4 0.92
card/tmpsets/set/mod016-card-mod-bar_and_box/self/style_media.rb 100.00 % 15 8 8 0 1.38
card/tmpsets/set/mod016-card-mod-bar_and_box/type/image.rb 59.09 % 47 22 13 9 0.73
card/tmpsets/set/mod017-card-mod-bootstrap/abstract/bootstrap_code_file.rb 94.29 % 66 35 33 2 12.91
card/tmpsets/set/mod017-card-mod-bootstrap/abstract/bootswatch_theme.rb 87.50 % 166 56 49 7 1.64
card/tmpsets/set/mod017-card-mod-bootstrap/abstract/bootswatch_theme/html_views.rb 60.00 % 39 20 12 8 0.80
card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/accordion.rb 28.57 % 72 28 8 20 0.43
card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/dropdown.rb 82.35 % 95 34 28 6 11.85
card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/form.rb 100.00 % 44 23 23 0 7.96
card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/helper.rb 40.00 % 62 40 16 24 1.00
card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/icon.rb 91.18 % 118 34 31 3 7.88
card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/navbar.rb 33.33 % 75 33 11 22 0.45
card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/table.rb 29.09 % 108 55 16 39 0.36
card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/tabs.rb 100.00 % 49 9 9 0 1.44
card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/wrapper.rb 93.33 % 28 15 14 1 8.80
card/tmpsets/set/mod017-card-mod-bootstrap/all/rich_bootstrap.rb 83.33 % 24 12 10 2 1.08
card/tmpsets/set/mod017-card-mod-bootstrap/self/bootstrap_core.rb 100.00 % 22 11 11 0 3.82
card/tmpsets/set/mod017-card-mod-bootstrap/self/bootstrap_functions.rb 100.00 % 14 7 7 0 1.29
card/tmpsets/set/mod017-card-mod-bootstrap/self/font_awesome.rb 100.00 % 11 6 6 0 1.33
card/tmpsets/set/mod017-card-mod-bootstrap/self/material_icons.rb 100.00 % 11 6 6 0 1.33
card/tmpsets/set/mod017-card-mod-bootstrap/self/script_bootstrap.rb 80.00 % 21 10 8 2 1.00
card/tmpsets/set/mod017-card-mod-bootstrap/self/script_load_select2.rb 100.00 % 11 6 6 0 1.33
card/tmpsets/set/mod017-card-mod-bootstrap/self/script_select2.rb 80.00 % 21 10 8 2 1.00
card/tmpsets/set/mod017-card-mod-bootstrap/self/smartmenu_css.rb 85.71 % 14 7 6 1 1.14
card/tmpsets/set/mod017-card-mod-bootstrap/self/smartmenu_js.rb 85.71 % 14 7 6 1 1.14
card/tmpsets/set/mod017-card-mod-bootstrap/self/style_bootstrap_cards.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod017-card-mod-bootstrap/self/style_bootstrap_colorpicker.rb 100.00 % 15 8 8 0 1.25
card/tmpsets/set/mod017-card-mod-bootstrap/self/style_select2.rb 100.00 % 19 10 10 0 1.60
card/tmpsets/set/mod017-card-mod-bootstrap/self/style_select2_bootstrap.rb 100.00 % 10 5 5 0 1.40
card/tmpsets/set/mod017-card-mod-bootstrap/type/bootswatch_skin.rb 100.00 % 24 9 9 0 1.22
card/tmpsets/set/mod017-card-mod-bootstrap/type/customized_bootswatch_skin.rb 41.18 % 124 68 28 40 0.46
card/tmpsets/set/mod017-card-mod-bootstrap/type/customized_bootswatch_skin/html_views.rb 65.22 % 45 23 15 8 0.87
card/tmpsets/set/mod017-card-mod-bootstrap/type_plus_right/customized_bootswatch_skin/colors.rb 44.23 % 122 52 23 29 0.56
card/tmpsets/set/mod018-card-mod-history/all/history.rb 75.00 % 118 56 42 14 115.54
card/tmpsets/set/mod018-card-mod-history/all/history/act_listing.rb 36.76 % 133 68 25 43 0.43
card/tmpsets/set/mod018-card-mod-history/all/history/actions.rb 46.27 % 133 67 31 36 9.40
card/tmpsets/set/mod018-card-mod-history/all/history/acts.rb 75.00 % 17 8 6 2 1.13
card/tmpsets/set/mod018-card-mod-history/all/history/events.rb 84.00 % 109 50 42 8 126.76
card/tmpsets/set/mod018-card-mod-history/all/history/last.rb 65.45 % 107 55 36 19 0.82
card/tmpsets/set/mod018-card-mod-history/all/history/revision.rb 40.00 % 74 40 16 24 5.35
card/tmpsets/set/mod018-card-mod-history/all/history/selected.rb 56.41 % 73 39 22 17 75.72
card/tmpsets/set/mod018-card-mod-history/all/history/views.rb 50.00 % 44 22 11 11 0.68
card/tmpsets/set/mod018-card-mod-history/all/history_bridge.rb 31.71 % 74 41 13 28 0.39
card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment.rb 67.19 % 121 64 43 21 7.36
card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/cloud.rb 35.62 % 142 73 26 47 1.42
card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/coded.rb 56.25 % 31 16 9 7 1.56
card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/local.rb 96.43 % 49 28 27 1 2.57
card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/paths.rb 91.43 % 67 35 32 3 64.74
card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/storage_type.rb 64.89 % 179 94 61 33 61.15
card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/upload_cache.rb 46.94 % 94 49 23 26 1.08
card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/web.rb 83.33 % 12 6 5 1 1.33
card/tmpsets/set/mod019-card-mod-carrierwave/all/file_utils.rb 63.64 % 50 22 14 8 1.00
card/tmpsets/set/mod019-card-mod-carrierwave/self/admin.rb 60.00 % 32 10 6 4 0.80
card/tmpsets/set/mod019-card-mod-carrierwave/self/favicon.rb 92.31 % 25 13 12 1 7.92
card/tmpsets/set/mod019-card-mod-carrierwave/self/new_file.rb 72.73 % 22 11 8 3 1.00
card/tmpsets/set/mod019-card-mod-carrierwave/self/new_image.rb 72.73 % 22 11 8 3 1.00
card/tmpsets/set/mod019-card-mod-carrierwave/type/file.rb 77.27 % 125 66 51 15 4.94
card/tmpsets/set/mod019-card-mod-carrierwave/type/image.rb 71.67 % 110 60 43 17 9.90
card/tmpsets/set/mod019-card-mod-carrierwave/type/image/html_views.rb 56.41 % 78 39 22 17 1.41
card/tmpsets/set/mod020-card-mod-date/all/calendar.rb 100.00 % 18 8 8 0 1.38
card/tmpsets/set/mod020-card-mod-date/self/datepicker.rb 83.33 % 15 6 5 1 1.17
card/tmpsets/set/mod020-card-mod-date/self/script_datepicker.rb 87.50 % 16 8 7 1 1.13
card/tmpsets/set/mod020-card-mod-date/self/script_datepicker_config.rb 100.00 % 13 7 7 0 1.29
card/tmpsets/set/mod020-card-mod-date/self/style_datepicker.rb 100.00 % 20 10 10 0 1.60
card/tmpsets/set/mod020-card-mod-date/type/date.rb 100.00 % 14 7 7 0 1.43
card/tmpsets/set/mod022-card-mod-follow/abstract/follow_option.rb 93.10 % 65 29 27 2 2.10
card/tmpsets/set/mod022-card-mod-follow/all/follow.rb 65.00 % 42 20 13 7 1.40
card/tmpsets/set/mod022-card-mod-follow/all/follow/follow_link.rb 50.00 % 69 30 15 15 0.57
card/tmpsets/set/mod022-card-mod-follow/all/follow/follow_link_views.rb 73.68 % 38 19 14 5 1.05
card/tmpsets/set/mod022-card-mod-follow/all/follow/followed_by.rb 71.05 % 79 38 27 11 33.11
card/tmpsets/set/mod022-card-mod-follow/all/follow/follower_ids.rb 62.32 % 130 69 43 26 16.64
card/tmpsets/set/mod022-card-mod-follow/all/follow/start_follow_link.rb 50.00 % 19 10 5 5 0.70
card/tmpsets/set/mod022-card-mod-follow/all/follow/stop_follow_link.rb 45.45 % 20 11 5 6 0.64
card/tmpsets/set/mod022-card-mod-follow/all/notify.rb 90.91 % 90 44 40 4 39.52
card/tmpsets/set/mod022-card-mod-follow/all/notify/base_views.rb 80.28 % 136 71 57 14 3.35
card/tmpsets/set/mod022-card-mod-follow/all/notify/html_views.rb 81.82 % 26 11 9 2 1.45
card/tmpsets/set/mod022-card-mod-follow/right/account.rb 54.55 % 24 11 6 5 0.73
card/tmpsets/set/mod022-card-mod-follow/right/follow.rb 43.33 % 127 60 26 34 0.48
card/tmpsets/set/mod022-card-mod-follow/right/follow_fields.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod022-card-mod-follow/right/followers.rb 71.43 % 32 14 10 4 0.93
card/tmpsets/set/mod022-card-mod-follow/right/following.rb 43.33 % 59 30 13 17 0.53
card/tmpsets/set/mod022-card-mod-follow/self/always.rb 81.82 % 22 11 9 2 1.00
card/tmpsets/set/mod022-card-mod-follow/self/created.rb 78.57 % 28 14 11 3 5.29
card/tmpsets/set/mod022-card-mod-follow/self/edited.rb 78.57 % 29 14 11 3 5.29
card/tmpsets/set/mod022-card-mod-follow/self/follow.rb 100.00 % 11 6 6 0 1.33
card/tmpsets/set/mod022-card-mod-follow/self/follow_defaults.rb 35.90 % 97 39 14 25 0.44
card/tmpsets/set/mod022-card-mod-follow/self/never.rb 81.82 % 22 11 9 2 1.00
card/tmpsets/set/mod022-card-mod-follow/type/cardtype.rb 66.67 % 30 15 10 5 0.87
card/tmpsets/set/mod022-card-mod-follow/type/set.rb 61.29 % 62 31 19 12 1.23
card/tmpsets/set/mod022-card-mod-follow/type/user.rb 55.56 % 16 9 5 4 0.78
card/tmpsets/set/mod022-card-mod-follow/type_plus_right/user/follow.rb 45.24 % 86 42 19 23 0.55
card/tmpsets/set/mod022-card-mod-follow/type_plus_right/user/follow/follow_editor_helper.rb 31.67 % 130 60 19 41 0.40
card/tmpsets/set/mod023-card-mod-google_analytics/all/google_analytics.rb 83.33 % 51 24 20 4 6.25
card/tmpsets/set/mod024-card-mod-markdown/type/markdown.rb 84.62 % 26 13 11 2 2.46
card/tmpsets/set/mod025-card-mod-prosemirror_editor/all/prosemirror_editor.rb 75.00 % 17 8 6 2 1.13
card/tmpsets/set/mod025-card-mod-prosemirror_editor/self/script_prosemirror.rb 100.00 % 13 7 7 0 1.29
card/tmpsets/set/mod025-card-mod-prosemirror_editor/self/script_prosemirror_config.rb 100.00 % 14 7 7 0 1.29
card/tmpsets/set/mod025-card-mod-prosemirror_editor/self/style_prosemirror.rb 100.00 % 12 6 6 0 1.33
card/tmpsets/set/mod026-card-mod-recaptcha/all/recaptcha.rb 62.00 % 111 50 31 19 16.96
card/tmpsets/set/mod026-card-mod-recaptcha/self/admin_info.rb 56.25 % 41 16 9 7 0.75
card/tmpsets/set/mod026-card-mod-recaptcha/self/recaptcha_proxy.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod026-card-mod-recaptcha/self/recaptcha_secret_key.rb 66.67 % 18 9 6 3 0.89
card/tmpsets/set/mod026-card-mod-recaptcha/self/recaptcha_settings.rb 85.71 % 53 7 6 1 1.29
card/tmpsets/set/mod026-card-mod-recaptcha/self/recaptcha_site_key.rb 66.67 % 18 9 6 3 0.89
card/tmpsets/set/mod027-card-mod-rules/right/self.rb 83.33 % 12 6 5 1 1.17
card/tmpsets/set/mod027-card-mod-rules/rstar/rule_user.rb 75.00 % 17 8 6 2 1.00
card/tmpsets/set/mod027-card-mod-rules/rule/bar_view.rb 46.94 % 101 49 23 26 0.53
card/tmpsets/set/mod027-card-mod-rules/rule/bridge_rules_editor.rb 55.56 % 37 18 10 8 0.72
card/tmpsets/set/mod027-card-mod-rules/rule/editor.rb 42.59 % 119 54 23 31 0.48
card/tmpsets/set/mod027-card-mod-rules/rule/html_views.rb 88.89 % 22 9 8 1 3.22
card/tmpsets/set/mod027-card-mod-rules/rule/quick_editor.rb 57.14 % 48 21 12 9 0.71
card/tmpsets/set/mod027-card-mod-rules/rule/rule_form.rb 37.14 % 66 35 13 22 0.46
card/tmpsets/set/mod027-card-mod-rules/rule/rule_form/buttons.rb 43.48 % 55 23 10 13 0.61
card/tmpsets/set/mod027-card-mod-rules/rule/rule_form/form_elements.rb 33.33 % 61 33 11 22 0.45
card/tmpsets/set/mod027-card-mod-rules/rule/rule_form/rule_set_radio.rb 36.17 % 91 47 17 30 0.40
card/tmpsets/set/mod027-card-mod-rules/rule/rule_form/set_selection.rb 39.13 % 48 23 9 14 0.57
card/tmpsets/set/mod027-card-mod-rules/rule/rules.rb 47.46 % 118 59 28 31 1.07
card/tmpsets/set/mod027-card-mod-rules/self/script_rules.rb 100.00 % 12 6 6 0 1.33
card/tmpsets/set/mod027-card-mod-rules/type/set.rb 51.61 % 116 62 32 30 8.10
card/tmpsets/set/mod027-card-mod-rules/type/set/html_views.rb 58.62 % 60 29 17 12 0.93
card/tmpsets/set/mod027-card-mod-rules/type/set/html_views/rule_lists.rb 50.00 % 51 26 13 13 0.69
card/tmpsets/set/mod027-card-mod-rules/type/set/html_views/template.rb 63.64 % 21 11 7 4 1.09
card/tmpsets/set/mod027-card-mod-rules/type/set/rules_filter.rb 46.43 % 69 28 13 15 0.61
card/tmpsets/set/mod027-card-mod-rules/type/set/setting_lists.rb 48.78 % 85 41 20 21 0.59
card/tmpsets/set/mod028-card-mod-tinymce_editor/all/reference_editor.rb 52.38 % 41 21 11 10 0.67
card/tmpsets/set/mod028-card-mod-tinymce_editor/all/reference_editor/link_editor.rb 57.89 % 42 19 11 8 0.79
card/tmpsets/set/mod028-card-mod-tinymce_editor/all/reference_editor/link_editor/link_parser.rb 52.38 % 43 21 11 10 0.67
card/tmpsets/set/mod028-card-mod-tinymce_editor/all/reference_editor/nest_editor.rb 33.33 % 185 87 29 58 0.38
card/tmpsets/set/mod028-card-mod-tinymce_editor/all/reference_editor/nest_image.rb 41.67 % 79 36 15 21 0.56
card/tmpsets/set/mod028-card-mod-tinymce_editor/all/tinymce_editor.rb 100.00 % 16 7 7 0 2.29
card/tmpsets/set/mod028-card-mod-tinymce_editor/self/script_tinymce.rb 100.00 % 13 7 7 0 1.29
card/tmpsets/set/mod028-card-mod-tinymce_editor/self/script_tinymce_config.rb 100.00 % 13 7 7 0 1.29
card/tmpsets/set/mod028-card-mod-tinymce_editor/self/tiny_mce.rb 83.33 % 16 6 5 1 1.17
card/tmpsets/set/mod030-card-mod-monkey/all/event_viz.rb 33.33 % 73 36 12 24 0.39
card/tmpsets/set/mod030-card-mod-monkey/all/view_viz.rb 38.89 % 32 18 7 11 0.56
card/tmpsets/set/mod030-card-mod-monkey/right/debug.rb 30.61 % 97 49 15 34 0.37

Formats ( 100.0% covered at 0.0 hits/line )

0 files in total.
0 relevant lines, 0 lines covered and 0 lines missed. ( 100.0% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line

Chunks ( 90.63% covered at 720.31 hits/line )

9 files in total.
331 relevant lines, 300 lines covered and 31 lines missed. ( 90.63% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
card/lib/card/content/chunk/abstract.rb 95.24 % 88 42 40 2 1818.88
card/mod/core/chunk/escaped_literal.rb 100.00 % 27 10 10 0 1.80
card/mod/core/chunk/keep_escaped_literal.rb 100.00 % 26 10 10 0 1.20
card/mod/core/chunk/link.rb 95.16 % 121 62 59 3 539.79
card/mod/core/chunk/nest.rb 92.42 % 127 66 61 5 1142.06
card/mod/core/chunk/query_reference.rb 96.30 % 95 27 26 1 85.00
card/mod/core/chunk/reference.rb 90.00 % 59 30 27 3 1567.60
card/mod/core/chunk/uri.rb 98.11 % 145 53 52 1 72.06
card/mod/core/chunk/view_stub.rb 48.39 % 62 31 15 16 0.48

Ungrouped ( 94.61% covered at 9.27 hits/line )

3 files in total.
167 relevant lines, 158 lines covered and 9 lines missed. ( 94.61% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line
decko/lib/decko/response.rb 90.91 % 170 88 80 8 7.39
decko/rails/controllers/application_controller.rb 100.00 % 2 1 1 0 1.00
decko/rails/controllers/card_controller.rb 98.72 % 151 78 77 1 11.50

card-mod-bootstrap/lib/card/lazy_tab.rb

95.0% lines covered

20 relevant lines. 19 lines covered and 1 lines missed.
    
  1. 1 class Card
  2. 1 class LazyTab < Tab
  3. 1 def url
  4. 94 @url ||= (config_hash? && @config[:path]) || format.path(view: view)
  5. end
  6. 1 def view
  7. 15 @view ||= (config_hash? && @config[:view]) || @config
  8. end
  9. 1 def tab_button
  10. 47 if url
  11. 47 super
  12. else
  13. wrap_with(:li, label, role: "presentation")
  14. end
  15. end
  16. 1 def button_attrib
  17. 141 @button_attrib ||= super.merge("data-url" => url.html_safe)
  18. end
  19. 1 def tab_button_link
  20. 47 add_class button_attrib, "load" unless active?
  21. 47 super
  22. end
  23. 1 def content
  24. 47 @content ||= ""
  25. end
  26. 1 def tab_pane args=nil, &block
  27. 47 @content = yield if active? && block_given?
  28. 47 super
  29. end
  30. end
  31. end

card-mod-bootstrap/lib/card/tab.rb

100.0% lines covered

40 relevant lines. 40 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 class Tab
  3. 1 attr_reader :format, :name, :label, :content, :button_attrib
  4. 1 class << self
  5. 1 def tab_objects format, tab_hash, active_name, klass=nil
  6. 29 klass ||= Card::Tab
  7. 29 active_name ||= tab_hash.keys.first
  8. 29 tab_hash.map do |name, config|
  9. 103 klass.new format, name, active_name, config
  10. end
  11. end
  12. end
  13. 1 delegate :add_class, :wrap_with, :unique_id, :link_to, to: :format
  14. 1 def initialize format, name, active_name, config
  15. 103 @format = format
  16. 103 @name = name
  17. 103 @active_name = active_name
  18. 103 @config = config
  19. end
  20. 1 def tab_button
  21. 103 add_class button_attrib, "active" if active?
  22. 103 wrap_with :li, tab_button_link,
  23. role: :presentation,
  24. class: "nav-item tab-li-#{name}"
  25. end
  26. 1 def tab_pane args=nil
  27. 103 pane_attr = { role: :tabpanel, id: tab_id }
  28. 103 pane_attr.merge! args if args.present?
  29. 103 add_class pane_attr, "tab-pane tab-pane-#{name}"
  30. 103 add_class pane_attr, "active" if active?
  31. 103 wrap_with :div, content, pane_attr
  32. end
  33. 1 private
  34. 1 def config_hash?
  35. 324 @config.is_a? Hash
  36. end
  37. 1 def label
  38. 103 @label ||= (config_hash? && @config[:title]) || name
  39. end
  40. 1 def content
  41. 56 @content ||= config_hash? ? @config[:content] : @config
  42. end
  43. 1 def button_attrib
  44. 174 @button_attrib ||= (config_hash? && @config[:button_attr]) || {}
  45. end
  46. 1 def tab_button_link
  47. 103 add_class button_attrib, "nav-link"
  48. 103 link_to label, button_attrib.merge(
  49. path: "##{tab_id}",
  50. role: "tab",
  51. "data-toggle" => "tab",
  52. "data-tab-name" => name
  53. )
  54. end
  55. 1 def tab_id
  56. 206 @tab_id ||= "#{unique_id}-#{name.to_name.safe_key}"
  57. end
  58. 1 def active?
  59. 300 name == @active_name
  60. end
  61. end
  62. end

card-mod-follow/lib/card/follower_stash.rb

97.83% lines covered

46 relevant lines. 45 lines covered and 1 lines missed.
    
  1. 1 class Card
  2. # stash followers of a given card
  3. 1 class FollowerStash
  4. 1 def initialize card=nil
  5. 112 @stash = Hash.new { |h, v| h[v] = [] }
  6. 54 @checked = ::Set.new
  7. 54 check_card(card) if card
  8. end
  9. 1 def check_card card
  10. 94 return if @checked.include? card.key
  11. 92 Auth.as_bot do
  12. 92 @checked.add card.key
  13. 92 stash_direct_followers card
  14. 92 stash_field_followers card.left
  15. end
  16. end
  17. 1 def followers
  18. @stash.keys
  19. end
  20. 1 def each_follower_with_reason
  21. # "follower"(=user) is a card object, "followed"(=reasons) a card name
  22. 54 @stash.each do |follower_card, reasons|
  23. 58 yield(follower_card, reasons.first)
  24. end
  25. end
  26. 1 private
  27. 1 def stash_direct_followers card
  28. 92 card.each_direct_follower_id_with_reason do |user_id, reason|
  29. 61 stash Card.fetch(user_id), reason
  30. end
  31. end
  32. 1 def stash_field_followers card
  33. 92 return unless (fields = follow_fields card)
  34. 31 fields.each do |field|
  35. 38 break if stash_field_follower card, field
  36. end
  37. end
  38. 1 def stash_field_follower card, field
  39. 38 return false unless checked?(field.to_name) || nested?(card, field)
  40. 7 check_card card
  41. 7 true
  42. end
  43. 1 def nested? card, field
  44. 35 return unless field.to_name.key == includes_card_key
  45. 30 @checked.intersection(nestee_set(card)).any?
  46. end
  47. 1 def includes_card_key
  48. 35 @includes_card_key ||= :nests.cardname.key
  49. end
  50. 1 def nestee_set card
  51. 30 @nestee_set ||= {}
  52. 30 @nestee_set[card.key] ||= nestee_search card
  53. end
  54. 1 def nestee_search card
  55. 30 Card.search({ return: "key", included_by: card.name },
  56. "follow cards included by #{card.name}")
  57. end
  58. 1 def checked? name
  59. 83 @checked.include? name.key
  60. end
  61. 1 def follow_fields card
  62. 92 return unless card && !checked?(card.name)
  63. 31 card.rule_card(:follow_fields)&.item_names(context: card.name)
  64. end
  65. 1 def stash follower, reason
  66. 61 @stash[follower] << reason
  67. end
  68. end
  69. end

card-mod-history/lib/card/act.rb

93.18% lines covered

44 relevant lines. 41 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 class Card
  3. # An "act" is a group of recorded {Card::Action actions} on {Card cards}.
  4. # Together, {Act acts}, {Action actions}, and {Change changes} comprise a
  5. # comprehensive {Card card} history tracking system.
  6. #
  7. # For example, if a given web form submissions updates the contents of three cards,
  8. # then the submission will result in the recording of three {Action actions}, each
  9. # of which is tied to one {Act act}.
  10. #
  11. # Each act records:
  12. #
  13. # - the _actor_id_ (an id associated with the account responsible)
  14. # - the _card_id_ of the act's primary card
  15. # - _acted_at_, a timestamp of the action
  16. # - the _ip_address_ of the actor where applicable.
  17. #
  18. 1 class Act < ApplicationRecord
  19. 1 before_save :assign_actor
  20. 2519 has_many :ar_actions, -> { order :id }, foreign_key: :card_act_id,
  21. inverse_of: :act,
  22. class_name: "Card::Action"
  23. 1 class << self
  24. # remove all acts that have no card. (janitorial)
  25. #
  26. # CAREFUL - could still have actions even if act card is gone...
  27. 1 def delete_cardless
  28. left_join = "LEFT JOIN cards ON card_acts.card_id = cards.id"
  29. joins(left_join).where("cards.id IS NULL").delete_all
  30. end
  31. # remove all acts that have no action. (janitorial)
  32. 1 def delete_actionless
  33. 2 joins(
  34. "LEFT JOIN card_actions ON card_acts.id = card_act_id"
  35. ).where(
  36. "card_actions.id is null"
  37. ).delete_all
  38. end
  39. # all acts with actions on a given list of cards
  40. # @param card_ids [Array of Integers]
  41. # @param with_drafts [true, false] (only shows drafts of current user)
  42. # @return [Array of Acts]
  43. 1 def all_with_actions_on card_ids, with_drafts=false
  44. 3 sql = "card_actions.card_id IN (:card_ids) AND (draft is not true"
  45. 3 sql << (with_drafts ? " OR actor_id = :user_id)" : ")")
  46. 3 all_viewable([sql, { card_ids: card_ids, user_id: Card::Auth.current_id }])
  47. end
  48. # all acts with actions that current user has permission to view
  49. # @return [ActiveRecord Relation]
  50. 1 def all_viewable action_where=nil
  51. 3 relation = joins(ar_actions: :ar_card)
  52. 3 relation = relation.where(action_where) if action_where
  53. 3 relation.where(Query::CardQuery.viewable_sql).where.not(card_id: nil).distinct
  54. end
  55. 1 def cache
  56. 362 Card::Cache[Card::Act]
  57. end
  58. # used by rails time_ago
  59. # timestamp is set by rails on create
  60. 1 def timestamp_attributes_for_create
  61. 1 super << "acted_at"
  62. end
  63. end
  64. 1 def actor
  65. 65 Card.fetch actor_id
  66. end
  67. # the act's primary card
  68. # @return [Card]
  69. 1 def card
  70. 94 Card.fetch card_id, look_in_trash: true # , skip_modules: true
  71. # FIXME: if the following is necessary, we need to document why.
  72. # generally it's a very bad idea to have type-specific code here.
  73. # return res unless res&.type_id&.in?([Card::FileID, Card::ImageID])
  74. # res.include_set_modules
  75. end
  76. # list of all actions that are part of the act
  77. # @return [Array]
  78. 1 def actions cached=true
  79. 416 return ar_actions unless cached
  80. 412 self.class.cache.fetch("#{id}-actions") { ar_actions.find_all.to_a }
  81. end
  82. # act's action on the card in question
  83. # @param card_id [Integer]
  84. # @return [Card::Action]
  85. 1 def action_on card_id
  86. 153 actions.find do |action|
  87. 153 action.card_id == card_id && !action.draft
  88. end
  89. end
  90. # act's action on primary card if it exists. otherwise act's first action
  91. # @return [Card::Action]
  92. 1 def main_action
  93. 152 action_on(card_id) || actions.first
  94. end
  95. 1 def draft?
  96. 2 main_action.draft
  97. end
  98. # time (in words) since act took place
  99. # @return [String]
  100. 1 def elapsed_time
  101. DateTime.new(acted_at).distance_of_time_in_words_to_now
  102. end
  103. # act's actions on either the card itself or another card that includes it
  104. # @param card [Card]
  105. # @return [Array of Actions]
  106. 1 def actions_affecting card
  107. 150 actions.select do |action|
  108. 223 (card.id == action.card_id) ||
  109. card.nestee_ids.include?(action.card_id)
  110. end
  111. end
  112. 1 private
  113. # used by before filter
  114. 1 def assign_actor
  115. 2455 self.actor_id ||= Auth.current_id
  116. end
  117. end
  118. end

card-mod-history/lib/card/act/act_renderer.rb

89.89% lines covered

89 relevant lines. 80 lines covered and 9 lines missed.
    
  1. 1 class Card
  2. 1 class Act
  3. 1 class ActRenderer
  4. 1 def initialize format, act, args
  5. 4 @format = format
  6. 4 @act = act
  7. 4 @act_card = act.card
  8. 4 @args = args
  9. 4 @card = @format.card
  10. 4 @context = @args[:act_context]
  11. end
  12. 1 include ::Bootstrapper
  13. 1 def method_missing method_name, *args, &block
  14. 56 if block_given?
  15. 8 @format.send(method_name, *args, &block)
  16. else
  17. 48 @format.send(method_name, *args)
  18. end
  19. end
  20. 1 def respond_to_missing? method_name, _include_private=false
  21. @format.respond_to? method_name
  22. end
  23. 1 def render
  24. 3 return "" unless @act_card
  25. 3 act_accordion
  26. end
  27. 1 def header
  28. #::Bootstrap.new(self).render do
  29. 3 bs_layout do
  30. 3 row xs: [10, 2] do
  31. 3 column do
  32. 3 html title
  33. 6 tag(:span, "text-muted pl-1 badge") { summary }
  34. end
  35. 3 column act_links, class: "text-right"
  36. end
  37. end
  38. # end
  39. end
  40. 1 def absolute_title
  41. 1 accordion_expand_link(@act_card.name)
  42. end
  43. 1 def details
  44. 3 approved_actions[0..20].map do |action|
  45. 3 Action::ActionRenderer.new(@format, action, action_header?,
  46. :summary).render
  47. end.join
  48. end
  49. 1 def summary
  50. 4 %i[create update delete draft].map do |type|
  51. 16 next unless count_types[type].positive?
  52. 4 "#{@format.action_icon type}<small> #{count_types[type]}</small>"
  53. end.compact.join "<small class='text-muted'> | </small>"
  54. end
  55. 1 def act_links
  56. [
  57. 1 link_to_history,
  58. 1 (link_to_act_card unless @act_card.trash)
  59. ].compact.join " "
  60. end
  61. 1 def link_to_act_card
  62. 1 link_to_card @act_card, icon_tag(:new_window), class: "_stop_propagation"
  63. end
  64. 1 def link_to_history
  65. 1 link_to_card @act_card, icon_tag(:history),
  66. path: { view: :history, look_in_trash: true },
  67. class: "_stop_propagation",
  68. rel: "nofollow"
  69. end
  70. 1 def approved_actions
  71. 11 @approved_actions ||= actions.select { |a| a.card&.ok?(:read) }
  72. # FIXME: should not need to test for presence of card here.
  73. end
  74. 1 def action_header?
  75. 3 true
  76. # @action_header ||= approved_actions.size != 1 ||
  77. # approved_actions[0].card_id != @format.card.id
  78. end
  79. 1 def count_types
  80. 20 @count_types ||=
  81. approved_actions.each_with_object(
  82. 16 Hash.new { |h, k| h[k] = 0 }
  83. ) do |action, type_cnt|
  84. 4 type_cnt[action.action_type] += 1
  85. end
  86. end
  87. 1 def edited_ago
  88. 4 return "" unless @act.acted_at
  89. 4 "#{time_ago_in_words(@act.acted_at)} ago"
  90. end
  91. 1 def collapse_id
  92. 16 "act-id-#{@act.id}"
  93. end
  94. 1 def accordion_expand_link text
  95. 3 <<-HTML
  96. <a>
  97. #{text}
  98. </a>
  99. HTML
  100. end
  101. # TODO: change accordion API in bootstrap/helper.rb so that it can be used
  102. # here. The problem is that here we have extra links in the title
  103. # that are not supposed to expand the accordion
  104. 1 def act_accordion
  105. 3 context = @act.main_action.draft ? :warning : :default
  106. 3 <<-HTML
  107. <div class="card card-#{context} nodblclick">
  108. #{act_accordion_panel}
  109. </div>
  110. HTML
  111. end
  112. 1 def accordion_expand_options
  113. {
  114. 3 "data-toggle" => "collapse",
  115. "data-target" => ".#{collapse_id}",
  116. "aria-expanded" => true,
  117. "aria-controls" => collapse_id
  118. }
  119. end
  120. 1 def act_panel_options
  121. 3 { class: "card-header", role: "tab", id: "heading-#{collapse_id}" }
  122. end
  123. 1 def act_accordion_panel
  124. 3 act_accordion_heading + act_accordion_body
  125. end
  126. 1 def act_accordion_heading
  127. 3 wrap_with :div, act_panel_options.merge(accordion_expand_options) do
  128. 3 wrap_with(:h5, header, class: "mb-0") + subtitle
  129. end
  130. end
  131. 1 def act_accordion_body
  132. 3 wrap_with :div, id: collapse_id,
  133. class: "collapse #{collapse_id}",
  134. "data-parent": ".act-accordion-group" do
  135. 3 wrap_with :div, details, class: "card-body"
  136. end
  137. end
  138. # Revert:
  139. # current update
  140. # Restore:
  141. # current deletion
  142. # Revert and Restore:
  143. # old deletions
  144. # blank:
  145. # current create
  146. # save as current:
  147. # not current, not deletion
  148. 1 def rollback_link
  149. 1 return unless card.ok? :update
  150. 1 wrap_with :div, class: "act-link collapse #{collapse_id} float-right" do
  151. 1 content_tag(:small, revert_link)
  152. # link_to "Save as current",
  153. # class: "slotter", remote: true,
  154. # method: :post, rel: "nofollow",
  155. # "data-slot-selector" => ".card-slot.history-view",
  156. # path: { action: :update, action_ids: prior,
  157. # view: :open, look_in_trash: true }
  158. end
  159. end
  160. 1 def deletion_act?
  161. act_type == :delete
  162. end
  163. 1 def act_type
  164. @act.main_action.action_type
  165. end
  166. 1 def show_or_hide_changes_link
  167. wrap_with :div, class: "act-link" do
  168. @format.link_to_view(
  169. :act, "#{@args[:hide_diff] ? 'Show' : 'Hide'} changes",
  170. path: { act_id: @args[:act].id, act_seq: @args[:act_seq],
  171. hide_diff: !@args[:hide_diff], action_view: :expanded,
  172. act_context: @args[:act_context], look_in_trash: true }
  173. )
  174. end
  175. end
  176. 1 def autosaved_draft_link opts={}
  177. text = opts.delete(:text) || "autosaved draft"
  178. opts[:path] = { edit_draft: true }
  179. add_class opts, "navbar-link"
  180. link_to_view :edit, text, opts
  181. end
  182. end
  183. end
  184. end

card-mod-history/lib/card/act/act_renderer/absolute_act_renderer.rb

100.0% lines covered

13 relevant lines. 13 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 class Act
  3. 1 class ActRenderer
  4. # Used for recent changes.
  5. # It shows all actions of an act
  6. 1 class AbsoluteActRenderer < ActRenderer
  7. 1 def title
  8. 1 absolute_title
  9. end
  10. 1 def subtitle
  11. 1 wrap_with :small do
  12. [
  13. 1 @format.link_to_card(@act.actor, nil, class: "_stop_propagation"),
  14. edited_ago,
  15. rollback_link
  16. ]
  17. end
  18. end
  19. # FIXME: how do we know we need main here??
  20. 1 def revert_link
  21. 1 revert_actions_link "revert to previous",
  22. { revert_to: :previous, revert_act: @act.id },
  23. "data-slot-selector": "#main > .card-slot"
  24. end
  25. 1 def actions
  26. 1 @act.actions
  27. end
  28. end
  29. end
  30. end
  31. end

card-mod-history/lib/card/act/act_renderer/bridge_act_renderer.rb

66.67% lines covered

27 relevant lines. 18 lines covered and 9 lines missed.
    
  1. 1 class Card
  2. 1 class Act
  3. 1 class ActRenderer
  4. # Used for the bridge
  5. 1 class BridgeActRenderer < RelativeActRenderer
  6. 1 def title
  7. 1 wrap_with(:div, left_title, class: "mr-2") +
  8. wrap_with(:div, right_title, class: "ml-auto act-summary")
  9. end
  10. 1 def left_title
  11. 1 ["##{@args[:act_seq]}", @act.actor.name, wrap_with(:small, edited_ago)].join " "
  12. end
  13. 1 def right_title
  14. 1 summary
  15. end
  16. 1 def render
  17. return "" unless @act_card
  18. details
  19. end
  20. 1 def bridge_link
  21. 1 opts = @format.bridge_link_opts(
  22. path: { act_id: @act.id, view: :bridge_act, act_seq: @args[:act_seq] },
  23. "data-toggle": "pill"
  24. )
  25. 1 add_class opts, "d-flex nav-link"
  26. 1 opts[:path].delete :layout
  27. 1 link_to_card @card, title, opts
  28. end
  29. 1 def overlay_title
  30. wrap_with :div do
  31. [left_title, summary,
  32. subtitle.present? ? subtitle : nil,
  33. rollback_or_edit_link].compact.join " | "
  34. end
  35. end
  36. 1 def rollback_or_edit_link
  37. if @act.draft?
  38. autosaved_draft_link text: "continue editing"
  39. elsif show_rollback_link?
  40. revert_link
  41. end
  42. end
  43. end
  44. end
  45. end
  46. end

card-mod-history/lib/card/act/act_renderer/relative_act_renderer.rb

80.77% lines covered

26 relevant lines. 21 lines covered and 5 lines missed.
    
  1. 1 class Card
  2. 1 class Act
  3. 1 class ActRenderer
  4. # Use for the history for one specific card
  5. # It shows only the actions of an act that are relevant
  6. # for the card of the format that renders the act.
  7. 1 class RelativeActRenderer < ActRenderer
  8. 1 def title
  9. 2 "<span class=\"nr\">##{@args[:act_seq]}</span>" +
  10. accordion_expand_link(@act.actor.name) +
  11. " " +
  12. wrap_with(:small, edited_ago)
  13. end
  14. 1 def subtitle
  15. 2 return "" unless @act.card_id != @format.card.id
  16. wrap_with :small, "act on #{absolute_title}"
  17. end
  18. 1 def act_links
  19. 2 return unless (content = rollback_or_edit_link)
  20. wrap_with :small, content
  21. end
  22. 1 def rollback_or_edit_link
  23. 2 if @act.draft?
  24. autosaved_draft_link text: "continue editing",
  25. class: "collapse #{collapse_id}"
  26. 2 elsif show_rollback_link?
  27. rollback_link
  28. end
  29. end
  30. 1 def show_rollback_link?
  31. 2 !current_act?
  32. end
  33. 1 def current_act?
  34. 2 return unless @format.card.last_act && @act
  35. 2 @act.id == @format.card.last_act.id
  36. end
  37. 1 def actions
  38. 3 @actions ||= @act.actions_affecting(@card)
  39. end
  40. 1 def revert_link
  41. revert_actions_link "revert to this",
  42. { revert_actions: actions.map(&:id) },
  43. class: "_close-modal",
  44. "data-slotter-mode": "update-modal-origin"
  45. end
  46. end
  47. end
  48. end
  49. end

card-mod-history/lib/card/action.rb

96.2% lines covered

79 relevant lines. 76 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 class Card
  3. # An _action_ is a group of {Card::Change changes} to a single {Card card}
  4. # that is recorded during an {Card::Act act}.
  5. # Together, {Act acts}, {Action actions}, and {Change changes} comprise a
  6. # comprehensive {Card card} history tracking system.
  7. #
  8. # For example, if a given web submission changes both the name and type of
  9. # a given card, that would be recorded as one {Action action} with two
  10. # {Change changes}. If there are multiple cards changed, each card would
  11. # have its own {Action action}, but the whole submission would still comprise
  12. # just one single {Act act}.
  13. #
  14. # An {Action} records:
  15. #
  16. # * the _card_id_ of the {Card card} acted upon
  17. # * the _card_act_id_ of the {Card::Act act} of which the action is part
  18. # * the _action_type_ (create, update, or delete)
  19. # * a boolean indicated whether the action is a _draft_
  20. # * a _comment_ (where applicable)
  21. #
  22. 1 class Action < ApplicationRecord
  23. 1 include Differ
  24. 1 extend Admin
  25. 1 belongs_to :act, foreign_key: :card_act_id, inverse_of: :ar_actions
  26. 1 belongs_to :ar_card, foreign_key: :card_id, inverse_of: :actions, class_name: "Card"
  27. 1 has_many :card_changes, foreign_key: :card_action_id,
  28. inverse_of: :action,
  29. dependent: :delete_all,
  30. class_name: "Card::Change"
  31. 1 belongs_to :super_action, class_name: "Action", inverse_of: :sub_actions
  32. 1 has_many :sub_actions, class_name: "Action", inverse_of: :super_action
  33. 1 scope :created_by, lambda { |actor_id|
  34. 2546 joins(:act).where "card_acts.actor_id = ?", actor_id
  35. }
  36. # these are the three possible values for action_type
  37. 1 TYPE_OPTIONS = %i[create update delete].freeze
  38. 1 after_save :expire
  39. 1 class << self
  40. # retrieve action from cache if available
  41. # @param id [id of Action]
  42. # @return [Action, nil]
  43. 1 def fetch id
  44. 37 cache.fetch id.to_s do
  45. 18 find id.to_i
  46. end
  47. end
  48. # cache object for actions
  49. # @return [Card::Cache]
  50. 1 def cache
  51. 5349 Card::Cache[Action]
  52. end
  53. 1 def all_with_cards
  54. joins :ar_card
  55. end
  56. 1 def all_viewable
  57. all_with_cards.where Query::CardQuery.viewable_sql
  58. end
  59. end
  60. # each action is associated with on and only one card
  61. # @return [Card]
  62. 1 def card
  63. 1122 Card.fetch card_id, look_in_trash: true
  64. # I'm not sure what the rationale for the following was/is, but it was causing
  65. # problems in cases where slot attributes are overridden (eg see #wrap_data in
  66. # sources on wikirate). The problem is the format object had the set modules but
  67. # the card didn't.
  68. #
  69. # My guess is that the need for the following had something to do with errors
  70. # associated with changed types. If so, the solution probably needs to handle
  71. # including the set modules associated with the type at the time of the action
  72. # rather than including no set modules at all.
  73. #
  74. # What's more, we _definitely_ don't want to hard code special behavior for
  75. # specific types in here!
  76. # , skip_modules: true
  77. # return res unless res && res.type_id.in?([Card::FileID, Card::ImageID])
  78. # res.include_set_modules
  79. end
  80. # remove action from action cache
  81. 1 def expire
  82. 4525 self.class.cache.delete id.to_s
  83. end
  84. # assign action_type (create, update, or delete)
  85. # @param value [Symbol]
  86. # @return [Integer]
  87. 1 def action_type= value
  88. 2300 write_attribute :action_type, TYPE_OPTIONS.index(value)
  89. end
  90. # retrieve action_type (create, update, or delete)
  91. # @return [Symbol]
  92. 1 def action_type
  93. 5124 return :draft if draft
  94. 5124 TYPE_OPTIONS[read_attribute(:action_type)]
  95. end
  96. 1 def previous_action
  97. 4 Card::Action.where("id < ? AND card_id = ?", id, card_id).last
  98. end
  99. # value set by action's {Change} to given field
  100. # @see #interpret_field #interpret_field for field param
  101. # @see #interpret_value #interpret_value for return values
  102. 1 def value field
  103. 743 return unless (change = change field)
  104. 568 interpret_value field, change.value
  105. end
  106. # value of field set by most recent {Change} before this one
  107. # @see #interpret_field #interpret_field for field param
  108. # @see #interpret_field #interpret_field for field param
  109. 1 def previous_value field
  110. 27 return if action_type == :create
  111. 3 return unless (previous_change = previous_change field)
  112. 3 interpret_value field, previous_change.value
  113. end
  114. # action's {Change} object for given field
  115. # @see #interpret_field #interpret_field for field param
  116. # @return [Change]
  117. 1 def change field
  118. 763 changes[interpret_field field]
  119. end
  120. # most recent change to given field before this one
  121. # @see #interpret_field #interpret_field for field param
  122. # @return [Change]
  123. 1 def previous_change field
  124. 3 return nil if action_type == :create
  125. 3 field = interpret_field field
  126. 3 if @previous_changes&.key?(field)
  127. @previous_changes[field]
  128. else
  129. 3 @previous_changes ||= {}
  130. 3 @previous_changes[field] = card.last_change_on field, before: self
  131. end
  132. end
  133. 1 def all_changes
  134. 313 self.class.cache.fetch("#{id}-changes") do
  135. # using card_changes causes caching problem
  136. 123 Card::Change.where(card_action_id: id).to_a
  137. end
  138. end
  139. # all action {Change changes} in hash form. { field1: Change1 }
  140. # @return [Hash]
  141. 1 def changes
  142. 766 @changes ||=
  143. 209 if sole?
  144. 107 current_changes
  145. else
  146. 102 all_changes.each_with_object({}) do |change, hash|
  147. 149 hash[change.field.to_sym] = change
  148. end
  149. end
  150. end
  151. # all changed values in hash form. { field1: new_value }
  152. 1 def changed_values
  153. 3 @changed_values ||= changes.each_with_object({}) do |(key, change), h|
  154. 18 h[key] = change.value
  155. end
  156. end
  157. # @return [Hash]
  158. 1 def current_changes
  159. 107 return {} unless card
  160. 107 @current_changes ||=
  161. Card::Change::TRACKED_FIELDS.each_with_object({}) do |field, hash|
  162. 642 hash[field.to_sym] = Card::Change.new field: field,
  163. value: card.send(field),
  164. card_action_id: id
  165. end
  166. end
  167. # translate field into fieldname as referred to in database
  168. # @see Change::TRACKED_FIELDS
  169. # @param field [Symbol] can be :type_id, :cardtype, :db_content, :content,
  170. # :name, :trash
  171. # @return [Symbol]
  172. 1 def interpret_field field
  173. 766 case field
  174. 125 when :content then :db_content
  175. 121 when :cardtype then :type_id
  176. 520 else field.to_sym
  177. end
  178. end
  179. # value in form prescribed for specific field name
  180. # @param value [value of {Change}]
  181. # @return [Integer] for :type_id
  182. # @return [String] for :name, :db_content, :content, :cardtype
  183. # @return [True/False] for :trash
  184. 1 def interpret_value field, value
  185. 571 case field.to_sym
  186. when :type_id
  187. 6 value&.to_i
  188. when :cardtype
  189. 57 Card.fetch_name(value&.to_i)
  190. 508 else value
  191. end
  192. end
  193. 1 def sole?
  194. 211 all_changes.empty? &&
  195. 119 (action_type == :create || Card::Action.where(card_id: card_id).count == 1)
  196. end
  197. end
  198. end

card-mod-history/lib/card/action/action_renderer.rb

93.62% lines covered

47 relevant lines. 44 lines covered and 3 lines missed.
    
  1. 1 class Card
  2. 1 class Action
  3. 1 class ActionRenderer
  4. 1 attr_reader :action, :header
  5. 1 def initialize format, action, header=true, action_view=:summary, hide_diff=false
  6. 3 @format = format
  7. 3 @action = action
  8. 3 @header = header
  9. 3 @action_view = action_view
  10. 3 @hide_diff = hide_diff
  11. end
  12. 1 include ::Bootstrapper
  13. 1 def method_missing method_name, *args, &block
  14. 33 if block_given?
  15. @format.send(method_name, *args, &block)
  16. else
  17. 33 @format.send(method_name, *args)
  18. end
  19. end
  20. 1 def respond_to_missing? method_name, _include_private=false
  21. @format.respond_to? method_name
  22. end
  23. 1 def render
  24. 3 classes = @format.classy("action-list")
  25. 3 bs_layout container: true, fluid: true do
  26. 3 row do
  27. 3 html <<-HTML
  28. <ul class="#{classes} w-100">
  29. <li class="#{action.action_type}">
  30. #{action_panel}
  31. </li>
  32. </ul>
  33. HTML
  34. end
  35. end
  36. end
  37. 1 def action_panel
  38. 3 bs_panel do
  39. 3 if header
  40. 3 heading do
  41. 3 div type_diff, class: "float-right"
  42. 3 div name_diff
  43. end
  44. end
  45. 3 body do
  46. 3 content_diff
  47. end
  48. end
  49. end
  50. 1 def name_diff
  51. 3 if @action.card == @format.card
  52. 3 name_changes
  53. else
  54. link_to_view(
  55. :related, name_changes,
  56. path: { slot: { items: { view: "history", nest_name: @action.card.name } } },
  57. # "data-slot-selector" => ".card-slot.history-view"
  58. )
  59. end
  60. end
  61. 1 def content_diff
  62. 3 return @action.raw_view if @action.action_type == :delete
  63. 3 @format.subformat(@action.card).render_action_summary action_id: @action.id
  64. end
  65. 1 def type_diff
  66. 3 return "" unless @action.new_type?
  67. 3 @hide_diff ? @action.value(:cardtype) : @action.cardtype_diff
  68. end
  69. 1 def name_changes
  70. 3 return old_name unless @action.new_name?
  71. 3 @hide_diff ? new_name : Card::Content::Diff.complete(old_name, new_name)
  72. end
  73. 1 def old_name
  74. 3 (name = @action.previous_value :name) && title_in_context(name)
  75. end
  76. 1 def new_name
  77. 3 title_in_context @action.value(:name)
  78. end
  79. end
  80. end
  81. end

card-mod-history/lib/card/action/admin.rb

57.89% lines covered

19 relevant lines. 11 lines covered and 8 lines missed.
    
  1. 1 class Card
  2. 1 class Action
  3. # methods for administering card actions
  4. 1 module Admin
  5. # permanently delete all {Action actions} not associated with a {Card}
  6. 1 def delete_cardless
  7. 1 left_join = "LEFT JOIN cards ON card_actions.card_id = cards.id"
  8. 1 joins(left_join).where("cards.id IS NULL").delete_all
  9. end
  10. # permanently delete all {Action actions} associate with non-current
  11. # {Change changes}
  12. 1 def delete_old
  13. 1 Card::Change.delete_all
  14. 1 Card.find_each(&:delete_old_actions)
  15. 1 Card::Act.delete_actionless
  16. end
  17. # If an act is given then all remaining actions will be attached to that act.
  18. # Otherwise the actions keep their acts.
  19. 1 def make_current_state_the_initial_state act=nil
  20. Card::Change.delete_all
  21. Card.find_each(&:delete_old_actions)
  22. action_update = { action_type: Card::Action::TYPE_OPTIONS.index(:create) }
  23. action_update[:card_act_id] = act.id if act
  24. Card::Action.update_all action_update
  25. if act
  26. Card::Act.where("id != :id", id: act.id).delete_all
  27. else
  28. Card::Act.delete_actionless
  29. end
  30. end
  31. end
  32. end
  33. end

card-mod-history/lib/card/action/differ.rb

90.0% lines covered

40 relevant lines. 36 lines covered and 4 lines missed.
    
  1. 1 class Card
  2. 1 class Action
  3. # a collection of methods for comparing actions
  4. 1 module Differ
  5. # compare action's name value with previous name value
  6. # @return [rendered diff]
  7. 1 def name_diff opts={}
  8. return unless new_name?
  9. diff_object(:name, opts).complete
  10. end
  11. # does action change card's name?
  12. # @return [true/false]
  13. 1 def new_name?
  14. 3 !value(:name).nil?
  15. end
  16. # @return [rendered diff]
  17. # compare action's cardtype value with previous cardtype value
  18. 1 def cardtype_diff opts={}
  19. 3 return unless new_type?
  20. 3 diff_object(:cardtype, opts).complete
  21. end
  22. # does action change card's type?
  23. # @return [true/false]
  24. 1 def new_type?
  25. 6 !value(:type_id).nil?
  26. end
  27. # @return [rendered diff]
  28. # compare action's content value with previous content value
  29. 1 def content_diff diff_type=:expanded, opts=nil
  30. 5 return unless new_content?
  31. 5 dobj = content_diff_object(opts)
  32. 5 diff_type == :summary ? dobj.summary : dobj.complete
  33. end
  34. # does action change card's content?
  35. # @return [true/false]
  36. 1 def new_content?
  37. 388 !value(:db_content).nil?
  38. end
  39. # test whether content was visibly removed
  40. # @return [true/false]
  41. 1 def red?
  42. content_diff_object.red?
  43. end
  44. # test whether content was visibly added
  45. # @return [true/false]
  46. 1 def green?
  47. content_diff_object.green?
  48. end
  49. 1 def raw_view content=nil
  50. 6 original_content = card.db_content
  51. 6 card.db_content = content || value(:db_content)
  52. 6 card.format.render_raw
  53. ensure
  54. 6 card.db_content = original_content
  55. end
  56. 1 def summary_diff_omits_content?
  57. 5 content_diff_object.summary_omits_content?
  58. end
  59. 1 private
  60. 1 def diff_object field, opts
  61. 3 Card::Content::Diff.new previous_value(field), value(field), opts
  62. end
  63. 1 def content_diff_object opts=nil
  64. 10 @diff ||= begin
  65. 5 diff_args = opts || card.include_set_modules.diff_args
  66. 5 previous_value = previous_value(:content)
  67. 5 previous = previous_value ? raw_view(previous_value) : ""
  68. 5 current = raw_view
  69. 5 Card::Content::Diff.new previous, current, diff_args
  70. end
  71. end
  72. end
  73. end
  74. end

card-mod-history/lib/card/change.rb

94.44% lines covered

18 relevant lines. 17 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 require 'activerecord-import'
  3. 1 class Card
  4. # A _change_ is an alteration to a card's name, type, content, or trash state.
  5. # Together, {Act acts}, {Action actions}, and {Change changes} comprise a
  6. # comprehensive {Card card} history tracking system.
  7. #
  8. # For example, if a given web submission changes both the name and type of
  9. # card, that would be recorded as one {Action action} with two
  10. # {Change changes}.
  11. #
  12. # A {Change} records:
  13. #
  14. # * the _field_ changed
  15. # * the new _value_ of that field
  16. # * the {Action action} of which the change is part
  17. #
  18. 1 class Change < ApplicationRecord
  19. 1 belongs_to :action, foreign_key: :card_action_id,
  20. inverse_of: :card_changes
  21. # lists the database fields for which changes are recorded
  22. 1 TRACKED_FIELDS = %w[name type_id db_content trash left_id right_id].freeze
  23. 1 class << self
  24. # delete all {Change changes} not associated with an {Action action}
  25. # (janitorial)
  26. 1 def delete_actionless
  27. 1 joins(
  28. "LEFT JOIN card_actions "\
  29. "ON card_changes.card_action_id = card_actions.id "
  30. ).where(
  31. "card_actions.id is null"
  32. ).pluck_in_batches(:id) do |group_ids|
  33. # used to be .delete_all here, but that was failing on large dbs
  34. 1 Rails.logger.info "deleting batch of changes"
  35. 1 where("id in (#{group_ids.join ','})").delete_all
  36. end
  37. end
  38. # Change fields are recorded as integers. #field_index looks up the
  39. # integer associated with a given field name.
  40. # @param value [String, Symbol]
  41. # @return [Integer]
  42. 1 def field_index value
  43. 8 value.is_a?(Integer) ? value : TRACKED_FIELDS.index(value.to_s)
  44. end
  45. # look up changes based on field name
  46. # @param value [String, Symbol]
  47. # @return [Change]
  48. 1 def find_by_field_name value
  49. find_by_field field_index(value)
  50. end
  51. end
  52. # set field value (integer)
  53. # @param value [String, Symbol]
  54. 1 def field= value
  55. 4080 write_attribute(:field, TRACKED_FIELDS.index(value.to_s))
  56. end
  57. # retrieve field name
  58. # @return [String]
  59. 1 def field
  60. 150 TRACKED_FIELDS[read_attribute(:field)]
  61. end
  62. end
  63. end

card-mod-machines/lib/card/machine.rb

57.89% lines covered

19 relevant lines. 11 lines covered and 8 lines missed.
    
  1. 1 class Card
  2. 1 module Machine
  3. 1 REFRESHED = "MACHINE_ASSETS_REFRESHED".freeze
  4. 1 class << self
  5. 1 def refresh_script_and_style
  6. 37 return unless refresh_script_and_style?
  7. Card.fetch(:all, :script)&.update_if_source_file_changed
  8. Card.fetch(:all, :style)&.update_if_source_file_changed
  9. end
  10. 1 private
  11. 1 def refresh_script_and_style?
  12. 37 case Cardio.config.machine_refresh
  13. when :eager then true
  14. when :cautious then cautious_refresh?
  15. 37 when :never then false
  16. else
  17. raise Card::Error,
  18. "unknown option for machine_refresh: #{Cardio.config.machine_refresh}"
  19. end
  20. end
  21. # only refresh when cache was cleared
  22. 1 def cautious_refresh?
  23. return false unless Card::Cache.persistent_cache
  24. return false if Card.cache.read REFRESHED
  25. Card.cache.write REFRESHED, true
  26. end
  27. end
  28. end
  29. end

card-mod-tinymce_editor/lib/card/reference/nest_parser.rb

97.44% lines covered

39 relevant lines. 38 lines covered and 1 lines missed.
    
  1. 1 class Card
  2. 1 class Reference
  3. # Extracts all information needed to generate the nest editor form
  4. # from a nest syntax string
  5. 1 class NestParser
  6. 1 NEST_OPTIONS = %i[view title show hide wrap help variant size params].freeze
  7. 1 attr_reader :name, :options, :item_options, :raw
  8. 1 def self.new nest_string, default_view, default_item_view
  9. 14 return super if nest_string.is_a? String
  10. 5 OpenStruct.new(name: "", field?: true,
  11. options: [[:view, default_view]], item_options: [],
  12. raw: "{{+|view: #{default_view}}}")
  13. end
  14. 1 def self.new_image name
  15. 5 OpenStruct.new(name: name, field?: true,
  16. options: [%i[view content], %i[size medium]],
  17. item_options: [],
  18. raw: "{{+#{name}|view: content; size: medium}}")
  19. end
  20. 1 def field?
  21. 6 @field
  22. end
  23. 1 def initialize nest_string, _default_view, default_item_view
  24. 9 @raw = nest_string
  25. 9 @default_item_view = default_item_view
  26. 9 nest = Card::Content::Chunk::Nest.new nest_string, nil
  27. 9 init_name nest.name
  28. 9 extract_item_options nest.options
  29. 9 @options = extract_options nest.options
  30. end
  31. 1 private
  32. 1 def init_name name
  33. 9 @field = name.to_name.simple_relative?
  34. 9 @name = @field ? name.to_s[1..-1] : name
  35. end
  36. 1 def extract_options options
  37. 21 Card::Reference::NestParser::NEST_OPTIONS.each_with_object([]) do |key, res|
  38. 189 next unless options[key]
  39. 42 if key.in? %i[show hide]
  40. 13 values = Card::View.normalize_list(options[key])
  41. 36 res.concat(values.map { |val| [key, val] })
  42. else
  43. 29 res << [key, options[key]]
  44. end
  45. end
  46. end
  47. 1 def extract_item_options options
  48. 9 @item_options = []
  49. 9 item_options = options[:items]
  50. 9 while item_options
  51. 12 next_item_options = item_options[:items]
  52. 12 @item_options << extract_options(item_options)
  53. 12 item_options = next_item_options
  54. end
  55. # @item_options << default_item_options
  56. end
  57. 1 def default_item_options
  58. [:view, @default_item_view]
  59. end
  60. end
  61. end
  62. end

card-mod-virtual/lib/card/virtual.rb

88.46% lines covered

52 relevant lines. 46 lines covered and 6 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 class Card
  3. # Model for the card_virtuals table.
  4. # It provides method to get and store content for virtual cards from
  5. # the card_virtuals table.
  6. 1 class Virtual < ApplicationRecord
  7. 1 def update new_content
  8. 68 update! content: new_content
  9. 68 new_content
  10. end
  11. 1 class << self
  12. 1 def create card, virtual_content=nil
  13. 152 validate_card card
  14. 152 virtual_content ||= block_given? ? yield : card.generate_virtual_content
  15. 152 virtual = new left_id: left_id(card), right_id: right_id(card),
  16. left_key: card.name.left_key,
  17. content: virtual_content
  18. 152 virtual.save!
  19. 152 virtual
  20. end
  21. 1 def create_or_update card, virtual_content
  22. 73 if (virtual_card = find_by_card(card))
  23. 67 virtual_card.update virtual_content
  24. else
  25. 6 create card, virtual_content
  26. end
  27. end
  28. 1 def fetch_content card, &block
  29. 184 find_content_by_card(card) || create(card, &block).content
  30. end
  31. 1 def fetch card, &block
  32. find_by_card(card) || create(card, &block)
  33. end
  34. 1 def refresh card
  35. 1 virtual = find_by_card(card)
  36. 1 return create(card) unless virtual
  37. 1 virtual.update card.generate_virtual_content
  38. end
  39. 1 def find_content_by_card card
  40. 184 where_card(card)&.pluck(:content)&.first
  41. end
  42. 1 def find_by_card card
  43. 77 where_card(card).take
  44. end
  45. 1 private
  46. 1 def where_card card
  47. 261 query = { right_id: right_id(card) }
  48. 261 if (lid = left_id(card))
  49. 47 query[:left_id] = lid
  50. else
  51. 214 query[:left_key] = card.name.left_key
  52. end
  53. 261 where query
  54. end
  55. 1 def left_id card
  56. 565 if card.junction?
  57. 565 card.left_id&.positive? ? card.left_id : card.left&.id
  58. else
  59. card.id
  60. end
  61. end
  62. 1 def right_id card
  63. 565 if card.junction?
  64. 565 card.right_id&.positive? ? card.right_id : card.right&.id
  65. else
  66. -2
  67. end
  68. end
  69. 1 def validate_card card
  70. 152 reason ||=
  71. 152 if card.junction?
  72. 152 "needs left_id" unless left_id(card)
  73. 152 "needs right_id" unless right_id(card)
  74. elsif !card.id
  75. "needs id"
  76. end
  77. 152 return unless reason
  78. raise Card::Error, card.name, "count not cacheable: card #{card.name} #{reason}"
  79. end
  80. end
  81. end
  82. end

card/lib/card/auth.rb

88.89% lines covered

18 relevant lines. 16 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 class Card
  3. # Singleton methods for account authentication and contextualization.
  4. #
  5. # Manages current user,
  6. # "as" user, and password verification.
  7. 1 module Auth
  8. 1 extend Permissions
  9. 1 extend Proxy
  10. 1 extend Setup
  11. 1 extend Current
  12. 1 @as_card = @as_id = @current_id = @current = nil
  13. 1 class << self
  14. # authenticate a user by their login name and unencrypted password.
  15. # @param email [String]
  16. # @param password [String]
  17. # @return [+*account card, nil]
  18. 1 def authenticate email, password
  19. 9 account = Auth.find_account_by_email email
  20. case
  21. 10 when !account then nil
  22. when !account.active? then nil
  23. when Card.config.no_authentication then account
  24. 7 when password_valid?(account, password.strip) then account
  25. end
  26. end
  27. # check whether password is correct for account card
  28. # @param account [+*account card]
  29. # @param password [String]
  30. 1 def password_valid? account, password
  31. 9 account.password == encrypt(password, account.salt)
  32. end
  33. # encrypt password string with the given salt.
  34. # @return [SHA1 String]
  35. 1 def encrypt password, salt
  36. 27 Digest::SHA1.hexdigest "#{salt}--#{password}--"
  37. end
  38. end
  39. end
  40. end

card/lib/card/auth/current.rb

91.78% lines covered

73 relevant lines. 67 lines covered and 6 lines missed.
    
  1. 1 class Card
  2. 1 module Auth
  3. # methods for setting current account
  4. 1 module Current
  5. # set current user in process and session
  6. 1 def signin cardish
  7. 2112 signin_id = Card.id(cardish) || Card::AnonymousID
  8. 2112 self.current_id = signin_id
  9. 2112 set_session_user signin_id
  10. end
  11. # current user is not anonymous
  12. # @return [true/false]
  13. 1 def signed_in?
  14. 507 current_id != Card::AnonymousID
  15. end
  16. # id of current user card.
  17. # @return [Integer]
  18. 1 def current_id
  19. 47849 @current_id ||= Card::AnonymousID
  20. end
  21. # current accounted card (must have +\*account)
  22. # @return [Card]
  23. 1 def current
  24. 462 if @current && @current.id == current_id
  25. 375 @current
  26. else
  27. 87 @current = Card[current_id]
  28. end
  29. end
  30. 1 def current_roles
  31. 96 @current_roles ||= [Card.fetch_name(:anyone_signed_in),
  32. current.fetch(:roles)&.item_names].flatten.compact
  33. end
  34. 1 def serialize
  35. 188 { as_id: as_id, current_id: current_id }
  36. end
  37. # @param auth_data [Integer|Hash] user id, user name, or a hash
  38. # @option auth_data [Integer] current_id
  39. # @option auth_data [Integer] as_id
  40. 1 def with auth_data
  41. 7 if auth_data.is_a?(Integer) || auth_data.is_a?(String)
  42. auth_data = { current_id: Card.id(auth_data) }
  43. end
  44. 7 tmp_current_id = current_id
  45. 7 tmp_as_id = as_id
  46. 7 tmp_current = @current
  47. 7 tmp_as_card = @as_card
  48. 7 tmp_current_roles = @current_roles
  49. # resets @as and @as_card
  50. 7 self.current_id = auth_data[:current_id]
  51. 7 @as_id = auth_data[:as_id] if auth_data[:as_id]
  52. 7 yield
  53. ensure
  54. 7 @current_id = tmp_current_id
  55. 7 @as_id = tmp_as_id
  56. 7 @current = tmp_current
  57. 7 @as_card = tmp_as_card
  58. 7 @current_roles = tmp_current_roles
  59. end
  60. # get session object from Env
  61. # return [Session]
  62. 1 def session
  63. 2151 Card::Env.session
  64. end
  65. # set current from token, api_key, or session
  66. 1 def signin_with opts={}
  67. 39 if opts[:token]
  68. signin_with_token opts[:token]
  69. 39 elsif opts[:api_key]
  70. signin_with_api_key opts[:api_key]
  71. else
  72. 39 signin_with_session
  73. end
  74. end
  75. # set the current user based on token
  76. 1 def signin_with_token token
  77. payload = Token.validate! token
  78. signin payload[:anonymous] ? Card::AnonymousID : payload[:user_id]
  79. end
  80. # set the current user based on api_key
  81. 1 def signin_with_api_key api_key
  82. 1 account = find_account_by_api_key api_key
  83. 1 unless account&.validate_api_key! api_key
  84. raise Card::Error::PermissionDenied, "API key authentication failed"
  85. end
  86. 1 signin account.left_id
  87. end
  88. # get :user id from session and set Auth.current_id
  89. 1 def signin_with_session
  90. 39 card_id = session_user
  91. 39 signin(card_id && Card.exists?(card_id) ? card_id : nil)
  92. end
  93. # find +\*account card by +\*api card
  94. # @param api_key [String]
  95. # @return [+*account card, nil]
  96. 1 def find_account_by_api_key api_key
  97. 1 find_account_by :api_key, api_key.strip
  98. end
  99. # find +\*account card by +\*email card
  100. # @param email [String]
  101. # @return [+*account card, nil]
  102. 1 def find_account_by_email email
  103. 35 find_account_by :email, email.strip.downcase
  104. end
  105. # general pattern for finding +\*account card based on field cards
  106. # @param fieldcode [Symbol] code of account field
  107. # @param value [String] content of field
  108. # @return [+*account card, nil]
  109. 1 def find_account_by fieldcode, value
  110. 36 Auth.as_bot do
  111. 36 Card.search({ right_id: Card::AccountID,
  112. right_plus: [Card::Codename.id(fieldcode), { content: value }] },
  113. "find +:account with +#{fieldcode} (#{value})").first
  114. end
  115. end
  116. 1 def session_user
  117. 39 session[session_user_key]
  118. end
  119. 1 def set_session_user card_id
  120. 2112 session[session_user_key] = card_id
  121. end
  122. 1 def session_user_key
  123. 2207 "user_#{database.underscore}".to_sym
  124. end
  125. 1 def database
  126. 2207 Rails.configuration.database_configuration.dig Rails.env, "database"
  127. end
  128. # set the id of the current user.
  129. 1 def current_id= card_id
  130. 2132 @current = @as_id = @as_card = @current_roles = nil
  131. 2132 card_id = card_id.to_i if card_id.present?
  132. 2132 @current_id = card_id
  133. end
  134. end
  135. end
  136. end

card/lib/card/auth/permissions.rb

96.88% lines covered

32 relevant lines. 31 lines covered and 1 lines missed.
    
  1. 1 class Card
  2. 1 module Auth
  3. # singleton permission methods
  4. 1 module Permissions
  5. # user has "root" permissions
  6. # @return [true/false]
  7. 1 def always_ok?
  8. 18917 usr_id = as_id
  9. 18917 case usr_id
  10. 7270 when Card::WagnBotID then true # cannot disable
  11. when nil then false
  12. else
  13. 11647 always_ok_usr_id? usr_id
  14. end
  15. end
  16. # specified user has root permission
  17. # @param usr_id [Integer]
  18. # @return [true/false]
  19. 1 def always_ok_usr_id? usr_id, force_cache_update=false
  20. 11647 always = always_cache
  21. 11647 if always[usr_id].nil? || force_cache_update
  22. 963 update_always_cache usr_id, admin?(usr_id)
  23. else
  24. 10684 always[usr_id]
  25. end
  26. end
  27. 1 def update_always_cache usr_id, value
  28. 977 always = always_cache
  29. 977 always = always.dup if always.frozen?
  30. 977 always[usr_id] = value
  31. 977 Card.cache.write "ALWAYS", always
  32. 977 value
  33. end
  34. 1 def always_cache
  35. 12624 Card.cache.read("ALWAYS") || {}
  36. end
  37. # list of names of cardtype cards that current user has perms to create
  38. # @return [Array of strings]
  39. 1 def createable_types
  40. type_names =
  41. 80 Auth.as_bot do
  42. 80 Card.search(
  43. { type: Card::CardtypeID, return: :name,
  44. not: { codename: ["in"] + Card.config.non_createable_types } },
  45. "find createable types"
  46. )
  47. end
  48. 80 type_names.select do |name|
  49. 3520 Card.new(type: name).ok? :create
  50. end.sort
  51. end
  52. # test whether user is an administrator
  53. # @param user_id [Integer]
  54. # @return [true/false]
  55. 1 def admin? user_id
  56. 963 has_role? user_id, Card::AdministratorID
  57. end
  58. 1 def has_role? user_id, role_id
  59. 963 return false unless user_id && role_id
  60. 963 Card[user_id].all_enabled_roles.include? role_id
  61. end
  62. end
  63. end
  64. end

card/lib/card/auth/proxy.rb

100.0% lines covered

27 relevant lines. 27 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 module Auth
  3. # mechanism for assuming permissions of another user.
  4. 1 module Proxy
  5. # operate with the permissions of another "proxy" user
  6. 1 def as given_user
  7. 5828 tmp_id = @as_id
  8. 5828 tmp_card = @as_card
  9. 5828 @as_id = get_user_id(given_user)
  10. 5828 @as_card = nil
  11. # we could go ahead and set as_card if given a card...
  12. 5828 @current_id = @as_id if @current_id.nil?
  13. 5828 return unless block_given?
  14. 5823 yield
  15. ensure
  16. 5828 if block_given?
  17. 5823 @as_id = tmp_id
  18. 5823 @as_card = tmp_card
  19. end
  20. end
  21. # operate with the permissions of WagnBot (administrator)
  22. 1 def as_bot &block
  23. 5235 as Card::WagnBotID, &block
  24. end
  25. # id of proxy user
  26. # @return [Integer]
  27. 1 def as_id
  28. 51548 @as_id || current_id
  29. end
  30. # proxy user card
  31. # @return [Card]
  32. 1 def as_card
  33. 11627 if @as_card && @as_card.id == as_id
  34. 10519 @as_card
  35. else
  36. 1108 @as_card = Card[as_id]
  37. end
  38. end
  39. # get card id from args of unknown type
  40. # @todo replace with general mechanism, eg #quick_fetch
  41. 1 def get_user_id user
  42. 5828 case user
  43. when NilClass then nil
  44. 487 when Card then user.id
  45. 5305 when Integer then user
  46. 36 else Card.fetch_id(user)
  47. end
  48. end
  49. end
  50. end
  51. end

card/lib/card/auth/setup.rb

71.43% lines covered

28 relevant lines. 20 lines covered and 8 lines missed.
    
  1. 1 class Card
  2. 1 module Auth
  3. # singleton methods for managing setup state
  4. 1 module Setup
  5. 1 NEEDS_SETUP = "NEEDS_SETUP".freeze
  6. # app is not totally set up yet
  7. # @return [true/false]
  8. 1 def needs_setup?
  9. 9 if @needs_setup == false || Card.cache.read(NEEDS_SETUP)&.to_s == "false"
  10. @needs_setup = false
  11. else
  12. 9 needs_setup_if_no_accounts
  13. end
  14. end
  15. # for testing setup
  16. 1 def simulate_setup! mode=true
  17. Card.cache.delete NEEDS_SETUP
  18. @needs_setup = nil
  19. @hidden_accounts = mode ? user_account_ids : nil
  20. end
  21. 1 def instant_account_activation
  22. simulate_needs_setup!
  23. yield
  24. ensure
  25. simulate_needs_setup! false
  26. end
  27. 1 private
  28. 1 def needs_setup_if_no_accounts
  29. 9 user_account_count.zero?.tap do |need|
  30. 9 Card.cache.write NEEDS_SETUP, false unless need
  31. end
  32. end
  33. 1 def user_account_ids
  34. as_bot { Card.search user_account_cql.merge(return: :id) }
  35. end
  36. 1 def user_account_cql
  37. # every deck starts with two accounts: WagnBot and Anonymous
  38. 9 { right_id: Card::AccountID, creator_id: ["ne", Card::WagnBotID] }
  39. end
  40. 1 def user_account_count
  41. 9 cql = user_account_cql
  42. 9 cql[:not] = { id: ["in"].concat(@hidden_accounts) } if @hidden_accounts
  43. 18 as_bot { Card.count_by_cql cql }
  44. end
  45. end
  46. end
  47. end

card/lib/card/auth/token.rb

84.21% lines covered

19 relevant lines. 16 lines covered and 3 lines missed.
    
  1. 1 require "jwt"
  2. 1 class Card
  3. 1 module Auth
  4. # methods for setting current account
  5. 1 module Token
  6. 1 SECRET_KEY = Rails.application.secrets.secret_key_base.to_s
  7. 1 class << self
  8. 1 def encode user_id, extra_payload={}
  9. 45 payload = { user_id: user_id, exp: expiration }.merge(extra_payload)
  10. 45 JWT.encode payload, SECRET_KEY
  11. end
  12. # returns Hash if valid, String error message if not
  13. 1 def validate! token
  14. payload = decode token
  15. raise Card::Error::PermissionDenied, payload if payload.is_a? String
  16. payload
  17. end
  18. 1 def decode token
  19. 8 decoded = JWT.decode(token, SECRET_KEY)[0]
  20. 4 HashWithIndifferentAccess.new decoded
  21. rescue JWT::DecodeError => error
  22. 4 error.message
  23. end
  24. 1 def expiration
  25. 45 Card.config.token_expiry.from_now.to_i
  26. end
  27. end
  28. end
  29. end
  30. end

card/lib/card/cache/persistent.rb

76.56% lines covered

64 relevant lines. 49 lines covered and 15 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 class Card
  3. 1 class Cache
  4. # _Persistent_ (or _Hard_) caches closely mirror the database and are
  5. # intended to be altered only upon database alterations.
  6. #
  7. # Unlike the database, the persistent cache stores records of records that
  8. # have been requested but are missing or, in the case of some {Card cards},
  9. # "virtual", meaning that they follow known patterns but do not exist in the
  10. # database.
  11. #
  12. # Most persistent cache implementations cannot store objects with singleton
  13. # classes, therefore {Card cards} generally must have set_modules
  14. # re-included after retrieval from the persistent cache.
  15. #
  16. 1 class Persistent
  17. 1 attr_accessor :prefix
  18. 1 class << self
  19. # name of current database; used here to insure that different databases
  20. # are cached separately
  21. # TODO: find better home for this method
  22. 1 def database_name
  23. 10 @database_name ||= (cfg = Cardio.config) &&
  24. 1 (dbcfg = cfg.database_configuration) &&
  25. dbcfg[Rails.env]["database"]
  26. end
  27. 1 def stamp
  28. 24 @stamp ||= Cardio.cache.fetch(stamp_key) { new_stamp }
  29. end
  30. # stamp generator
  31. 1 def new_stamp
  32. 17 Time.now.to_i.to_s(36) + rand(999).to_s(36)
  33. end
  34. 1 def stamp_key
  35. 1 "#{database_name}-stamp"
  36. end
  37. 1 def renew
  38. @stamp = nil
  39. end
  40. 1 def reset
  41. @stamp = new_stamp
  42. Cardio.cache.write stamp_key, @stamp
  43. end
  44. end
  45. # @param opts [Hash]
  46. # @option opts [Rails::Cache] :store
  47. # @option opts [ruby Class] :class, typically ActiveRecord descendant
  48. # @option opts [String] :database
  49. 1 def initialize opts
  50. 11 @store = opts[:store]
  51. 11 @klass = opts[:class]
  52. 11 @class_key = @klass.to_s.to_name.key
  53. 11 @database = opts[:database] || self.class.database_name
  54. end
  55. # renew insures you're using the most current cache version by
  56. # reaffirming the stamp and prefix
  57. 1 def renew
  58. 67 @stamp = nil
  59. 67 @prefix = nil
  60. end
  61. # reset effectively clears the cache by setting a new stamp. However
  62. # unlike annihilate, it won't bother other apps using the same cache engine.
  63. 1 def reset
  64. 12 @stamp = self.class.new_stamp
  65. 12 @prefix = nil
  66. 12 Cardio.cache.write stamp_key, @stamp
  67. end
  68. # the nuclear option. can affect other applications sharing the same
  69. # cache engine. keep in mind mutually assured destruction.
  70. 1 def annihilate
  71. @store.clear
  72. end
  73. # the current time stamp. changing this value effectively resets
  74. # the cache. Note that Cardio.cache is a simple Rails::Cache, not
  75. # a Card::Cache object.
  76. 1 def stamp
  77. 16 @stamp ||= Cardio.cache.fetch(stamp_key) { self.class.new_stamp }
  78. end
  79. # key for looking up the current stamp
  80. 1 def stamp_key
  81. 23 "#{@database}-#{@class_key}-#{self.class.stamp}-stamp"
  82. end
  83. # prefix added to cache key to create a system-wide unique key
  84. 1 def prefix
  85. 21 @prefix ||= "#{@database}-#{@class_key}-#{stamp}:"
  86. end
  87. # returns prefix/key
  88. # @param key [String]
  89. # @return [String]
  90. 1 def full_key key
  91. 13 "#{prefix}/#{key}"
  92. end
  93. 1 def read key
  94. 6 @store.read full_key(key)
  95. end
  96. # update an attribute of an object already in the cache
  97. # @param key [String]
  98. # @param attribute [String, Symbol]
  99. 1 def write_attribute key, attribute, value
  100. return value unless @store
  101. if (object = deep_read key)
  102. object.instance_variable_set "@#{attribute}", value
  103. write key, object
  104. end
  105. value
  106. end
  107. 1 def deep_read key
  108. local_cache = @store.send :local_cache
  109. local_cache&.clear
  110. read key
  111. end
  112. 1 def read_attribute key, attribute
  113. object = deep_read key
  114. object.instance_variable_get "@#{attribute}"
  115. end
  116. 1 def write key, value
  117. 5 @store.write full_key(key), value
  118. end
  119. 1 def fetch key, &block
  120. 1 @store.fetch full_key(key), &block
  121. end
  122. 1 def delete key
  123. 1 @store.delete full_key(key)
  124. end
  125. 1 def exist? key
  126. @store.exist? full_key(key)
  127. end
  128. end
  129. end
  130. end

card/lib/card/content.rb

86.11% lines covered

72 relevant lines. 62 lines covered and 10 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 class Card
  3. # Content objects support the parsing of content strings into arrays that
  4. # contain semantically meaningful "chunks" like nests, links, urls, etc.
  5. #
  6. # Each chunk has an object whose class inherits from {Card::Content::Chunk::Abstract}
  7. #
  8. 1 class Content < SimpleDelegator
  9. 1 extend Clean
  10. 1 extend Truncate
  11. 1 Chunk # trigger autoload
  12. 1 attr_reader :revision, :format, :chunks, :opts
  13. # initialization parses String, detects chunks
  14. # @param content [String]
  15. # @param format_or_card [Card::Format or Card]
  16. # @param opts [Hash]
  17. # @option opts [Symbol] :chunk_list - name of registered list of chunk
  18. # classes to be used in parsing
  19. 1 def initialize content, format_or_card, opts={}
  20. 4237 @format = resolve_format format_or_card
  21. 4237 opts ||= {}
  22. 4237 chunk_list = opts[:chunk_list] || @format.chunk_list
  23. 4237 @chunks = Parser.new(chunk_list, self).parse(content)
  24. 4237 super(@chunks.any? ? @chunks : content)
  25. end
  26. # Content must be associated with a Format object, which in turn must be
  27. # associated with a Card
  28. # @return [Card]
  29. 1 def card
  30. 5539 @format.card
  31. end
  32. # Find all chunks of a given type
  33. # @param chunk_type [Chunk Class]
  34. # @return [Array of Chunk instances]
  35. 1 def find_chunks chunk_type
  36. 6327 each_chunk.select { |chunk| chunk.is_a?(chunk_type) }
  37. end
  38. 1 def has_chunk? chunk_type
  39. each_chunk.any { |chunk| chunk.is_a?(chunk_type) }
  40. end
  41. # sends &block to #process_chunk on each Chunk object
  42. 1 def process_chunks &block
  43. 1286 return custom_process_chunks(&block) if block_given?
  44. 1220 each_chunk(&:process_chunk)
  45. end
  46. 1 def custom_process_chunks
  47. 66 each_chunk do |chunk|
  48. 252 chunk.burn_after_reading yield(chunk)
  49. end
  50. end
  51. 1 def pieces
  52. 3 Array.wrap(__getobj__)
  53. end
  54. 1 def each_chunk
  55. 7025 return enum_for(:each_chunk) unless block_given?
  56. iterator =
  57. 4169 case __getobj__
  58. when Hash then :each_value
  59. 2401 when Array then :each
  60. 1768 when String then return # no chunks
  61. else
  62. Rails.logger.warn "unrecognized type for #each_chunk: " \
  63. " #{self.class} #{__getobj__.class}"
  64. return
  65. end
  66. 14681 send(iterator) { |item| yield item if item.is_a?(Chunk::Abstract) }
  67. end
  68. # convert content to String.
  69. # the common cases here are that either
  70. #
  71. # - (a) content is already a String, or
  72. # - (b) it's an Array that needs to be iterated over and converted into a
  73. # a string by running to_s on each item.
  74. 1 def to_s
  75. 1346 case __getobj__
  76. 937 when Array then map(&:to_s) * ""
  77. 409 when String then __getobj__
  78. when NilClass then "" # raise "Nil Card::Content"
  79. else __getobj__.to_s
  80. end
  81. end
  82. 1 def inspect
  83. "<#{__getobj__.class}:#{card}:#{self}>"
  84. end
  85. 1 def without_nests
  86. without_chunks Chunk::Nest do |content|
  87. yield content
  88. end
  89. end
  90. 1 def without_references
  91. 22 without_chunks Chunk::Nest, Chunk::Link do |content|
  92. 22 yield content
  93. end
  94. end
  95. 1 def without_chunks *chunk_classes
  96. 22 chunk_classes = ::Set.new Array.wrap(chunk_classes)
  97. 22 stash = stash_chunks chunk_classes
  98. 22 processed = yield to_s
  99. 22 unstash_chunks processed, stash
  100. end
  101. 1 private
  102. 1 def stash_chunks chunk_classes
  103. 22 chunks = []
  104. 22 each_chunk do |chunk|
  105. 21 next unless chunk_classes.include? chunk.class
  106. 21 chunk.burn_after_reading "{{#{chunks.size}}}"
  107. 21 chunks << chunk.text
  108. end
  109. 22 chunks
  110. end
  111. 1 def unstash_chunks content, stashed_chunks
  112. 22 Chunk::Nest.gsub content do |nest_content|
  113. 21 number?(nest_content) ? stashed_chunks[nest_content.to_i] : "{{#{nest_content}}}"
  114. end
  115. end
  116. 1 def resolve_format format_or_card
  117. 4237 if format_or_card.is_a?(Card)
  118. 2909 Format.new format_or_card, format: nil
  119. else
  120. 1328 format_or_card
  121. end
  122. end
  123. 1 def number? str
  124. 21 true if Float(str)
  125. rescue StandardError
  126. false
  127. end
  128. end
  129. end

card/lib/card/content/chunk.rb

95.65% lines covered

46 relevant lines. 44 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 require "uri/common"
  3. 1 class Card
  4. 1 class Content < SimpleDelegator
  5. # A chunk is a pattern of text that can be protected
  6. # and interrogated by a format. Each Chunk class has a
  7. # +pattern+ that states what sort of text it matches.
  8. # Chunks are initalized by passing in the result of a
  9. # match by its pattern.
  10. #
  11. 1 module Chunk
  12. 1 mattr_accessor :raw_list, :prefix_regexp_by_list,
  13. :prefix_map_by_list, :prefix_map_by_chunkname
  14. 1 @@raw_list = {}
  15. 1 @@prefix_regexp_by_list = {}
  16. 1 @@prefix_map_by_chunkname = {}
  17. 1 @@prefix_map_by_list = Hash.new { |h, k| h[k] = {} }
  18. 1 class << self
  19. 1 def register_class klass, hash
  20. 9 klass.config = hash.merge class: klass
  21. 9 prefix_index = hash[:idx_char] || :default
  22. # ^ this is gross and needs to be moved out.
  23. 9 klassname = klass.name.split("::").last.to_sym
  24. 9 prefix_map_by_chunkname[klassname] = { prefix_index => klass.config }
  25. 9 raw_list.each do |key, list|
  26. 54 next unless list.include? klassname
  27. 15 prefix_map_by_list[key].merge! prefix_map_by_chunkname[klassname]
  28. end
  29. end
  30. 1 def register_list key, list
  31. 6 raw_list[key] = list
  32. 6 prefix_map_by_list[key] =
  33. list.each_with_object({}) do |chunkname, h|
  34. 15 next unless (p_map = prefix_map_by_chunkname[chunkname])
  35. h.merge! p_map
  36. end
  37. end
  38. 1 def find_class_by_prefix prefix, chunk_list_key=:default
  39. 6332 validate_chunk_list_key chunk_list_key
  40. 6332 prefix_map = prefix_map_by_list[chunk_list_key]
  41. 6332 config = prefix_map[prefix[0, 1]] ||
  42. prefix_map[prefix[-1, 1]] ||
  43. prefix_map[:default]
  44. # prefix identified by first character, last character, or default.
  45. # a little ugly...
  46. 6332 config[:class]
  47. end
  48. 1 def prefix_regexp chunk_list_key
  49. 4237 prefix_regexp_by_list[chunk_list_key] ||=
  50. build_prefix_regexp chunk_list_key
  51. end
  52. 1 def build_prefix_regexp chunk_list_key
  53. 5 validate_chunk_list_key chunk_list_key
  54. prefix_res =
  55. 5 raw_list[chunk_list_key].map do |chunkname|
  56. 14 chunk_class = const_get chunkname
  57. 14 chunk_class.config[:prefix_re]
  58. end
  59. 5 /(?:#{ prefix_res * '|' })/m
  60. end
  61. 1 def validate_chunk_list_key chunk_list_key
  62. 6337 unless raw_list.key? chunk_list_key
  63. raise ArgumentError, "invalid chunk list key: #{chunk_list_key}"
  64. end
  65. end
  66. end
  67. # not sure whether this is best place.
  68. # Could really happen almost anywhere
  69. # (even before chunk classes are loaded).
  70. 1 register_list :default, %i[
  71. URI HostURI EmailURI EscapedLiteral Nest Link
  72. ]
  73. 1 register_list :references, %i[EscapedLiteral Nest Link]
  74. 1 register_list :nest_only, [:Nest]
  75. 1 register_list :query, [:QueryReference]
  76. 1 register_list :stub, [:ViewStub]
  77. 1 register_list :references_keep_escaping, %i[KeepEscapedLiteral Nest Link]
  78. end
  79. end
  80. 1 Card::Mod::Loader.load_chunks
  81. end

card/lib/card/content/chunk/abstract.rb

95.24% lines covered

42 relevant lines. 40 lines covered and 2 lines missed.
    
  1. 1 class Card
  2. 1 class Content < SimpleDelegator
  3. # A chunk is a pattern of text that can be protected
  4. # and interrogated by a format. Each Chunk class has a
  5. # +pattern+ that states what sort of text it matches.
  6. # Chunks are initalized by passing in the result of a
  7. # match by its pattern.
  8. #
  9. 1 module Chunk
  10. 1 class Abstract
  11. 1 class_attribute :config
  12. 1 attr_reader :text, :process_chunk
  13. 1 class << self
  14. # if the prefix regex matched check that chunk against the full regex
  15. 1 def full_match content, prefix=nil
  16. 6352 content.match full_re(prefix)
  17. end
  18. 1 def full_re _prefix
  19. 6345 config[:full_re]
  20. end
  21. 1 def context_ok? _content, _chunk_start
  22. 6092 true
  23. end
  24. end
  25. 1 def reference_code
  26. 1039 "I"
  27. end
  28. 1 def initialize match, content
  29. 6320 match = self.class.full_match(match) if match.is_a? String
  30. 6320 @text = match[0]
  31. 6320 @processed = nil
  32. 6320 @content = content
  33. 6320 interpret match, content
  34. end
  35. 1 def interpret _match_string, _content
  36. Rails.logger.info "no #interpret method found for chunk class: " \
  37. "#{self.class}"
  38. end
  39. 1 def format
  40. 9735 @content.format
  41. end
  42. 1 def card
  43. 5539 @content.card
  44. end
  45. 1 def to_s
  46. 2834 result
  47. end
  48. 1 def result
  49. 2834 burn_read || @process_chunk || @processed || @text
  50. end
  51. 1 def burn_read
  52. 2872 return unless @burn_read
  53. 273 tmp = @burn_read
  54. 273 @burn_read = nil
  55. 273 tmp
  56. end
  57. # Temporarily overrides the processed nest content for single-use
  58. # After using the nest's result
  59. # (for example via `to_s`) the original result is restored
  60. 1 def burn_after_reading text
  61. 273 @burn_read = text
  62. end
  63. 1 def inspect
  64. "<##{self.class}##{self}>"
  65. end
  66. 1 def as_json _options={}
  67. 38 burn_read || @process_chunk || @processed ||
  68. "not rendered #{self.class}, #{card&.name}"
  69. end
  70. end
  71. end
  72. end
  73. end

card/lib/card/content/clean.rb

100.0% lines covered

50 relevant lines. 50 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 class Content
  3. # tools for cleaning content, especially for restricing unwanted HTML
  4. 1 module Clean
  5. 1 allowed_tags = {}
  6. %w[
  7. 1 br i b pre cite caption strong em ins sup sub del ol hr ul li p
  8. div h1 h2 h3 h4 h5 h6 span table tr td th tbody thead tfoot
  9. 32 ].each { |tag| allowed_tags[tag] = [] }
  10. # allowed attributes
  11. 1 allowed_tags.merge!(
  12. "a" => %w[href title target],
  13. "img" => %w[src alt title],
  14. "code" => ["lang"],
  15. "blockquote" => ["cite"]
  16. )
  17. 1 if Cardio.config.allow_inline_styles
  18. 1 allowed_tags["table"] += %w[cellpadding align border cellspacing data-mce-style]
  19. 1 allowed_tags["td"] += %w[scope data-mce-style]
  20. 1 allowed_tags["th"] += %w[scope data-mce-style]
  21. end
  22. 1 allowed_tags.each_key do |k|
  23. 36 allowed_tags[k] << "class"
  24. 36 allowed_tags[k] << "style" if Cardio.config.allow_inline_styles
  25. 36 allowed_tags[k]
  26. end
  27. 1 ALLOWED_TAGS = allowed_tags.freeze
  28. 1 ATTR_VALUE_RE = [/(?<=^')[^']+(?=')/, /(?<=^")[^"]+(?=")/, /\S+/].freeze
  29. 1 def clean! string, tags=ALLOWED_TAGS
  30. 2402 cleaned = clean_tags string, tags
  31. 2402 cleaned = clean_spaces cleaned if Cardio.config.space_last_in_multispace
  32. 2402 cleaned
  33. end
  34. 1 private
  35. ## Method that cleans the String of HTML tags
  36. ## and attributes outside of the allowed list.
  37. 1 def clean_tags string, ok_tags
  38. # $LAST_MATCH_INFO is nil if string is a SafeBuffer
  39. 2402 string.to_str.gsub(%r{<(/*)(\w+)([^>]*)>}) do |_raw|
  40. 477 clean_tag $LAST_MATCH_INFO, ok_tags
  41. end.gsub(/<\!--.*?-->/, "")
  42. end
  43. 1 def clean_spaces string
  44. 2402 string.gsub(/(?:^|\b) ((?:&nbsp;)+)/, '\1 ')
  45. end
  46. 1 def clean_tag match, ok_tags
  47. 477 tag = match[2].downcase
  48. 477 return " " unless (ok_attrs = ok_tags[tag])
  49. 423 "<#{match[1]}#{html_attribs tag, match[3], ok_attrs}>"
  50. end
  51. 1 def html_attribs tag, raw_attr, ok_attrs
  52. 423 ok_attrs.each_with_object([tag]) do |ok_attr, pcs|
  53. 863 q, rest_value = process_attribute ok_attr, raw_attr
  54. 863 pcs << "#{ok_attr}=#{q}#{rest_value}#{q}" unless rest_value.blank?
  55. end * " "
  56. end
  57. 1 def process_attribute attrib, all_attributes
  58. 863 return ['"', nil] unless all_attributes =~ /\b#{attrib}\s*=\s*(?=(.))/i
  59. 14 q = '"'
  60. 14 rest_value = $'
  61. 14 if (idx = %w[' "].index Regexp.last_match(1))
  62. 13 q = Regexp.last_match(1)
  63. end
  64. 14 reg_exp = ATTR_VALUE_RE[idx || 2]
  65. 14 rest_value = process_attribute_match rest_value, reg_exp, attrib
  66. 14 [q, rest_value]
  67. end
  68. # NOTE allows classes beginning with "w-" (deprecated)
  69. 1 def process_attribute_match rest_value, reg_exp, attrib
  70. 14 return rest_value unless (match = rest_value.match reg_exp)
  71. 14 rest_value = match[0]
  72. 14 if attrib == "class"
  73. 22 rest_value.split(/\s+/).select { |s| s =~ /^w-/i }.join(" ")
  74. else
  75. 6 rest_value
  76. end
  77. end
  78. end
  79. end
  80. end

card/lib/card/content/diff.rb

100.0% lines covered

33 relevant lines. 33 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 class Card
  3. 1 class Content
  4. 1 class Diff
  5. 1 class << self
  6. 1 def complete a, b, opts={}
  7. 13 Card::Content::Diff.new(a, b, opts).complete
  8. end
  9. 1 def summary a, b, opts={}
  10. 8 Card::Content::Diff.new(a, b, opts).summary
  11. end
  12. 1 def render_added_chunk text
  13. 53 "<ins class='diffins diff-added'>#{text}</ins>"
  14. end
  15. 1 def render_deleted_chunk text, _count=true
  16. 38 "<del class='diffdel diff-deleted'>#{text}</del>"
  17. end
  18. end
  19. 1 attr_reader :result
  20. 1 delegate :summary, :complete, :summary_omits_content?, to: :result
  21. # diff options
  22. # :format => :html|:text|:pointer|:raw
  23. # :html = maintain html structure, but compare only content
  24. # :text = remove all html tags; compare plain text
  25. # :pointer = remove all double square brackets
  26. # :raw = escape html tags and compare everything
  27. #
  28. # summary: {length: <number> , joint: <string> }
  29. 1 def initialize old_version, new_version, opts={}
  30. 33 @result = Result.new opts[:summary]
  31. 33 return unless new_version
  32. 33 lcs_opts = lcs_opts_for_format opts[:diff_format]
  33. 33 LCS.new(lcs_opts).run(old_version, new_version, @result)
  34. end
  35. 1 def red?
  36. 4 @result.dels_cnt > 0
  37. end
  38. 1 def green?
  39. 4 @result.adds_cnt > 0
  40. end
  41. 1 private
  42. 1 def lcs_opts_for_format diff_format
  43. 33 opts = {}
  44. 33 case diff_format
  45. when :html
  46. 8 opts[:exclude] = /^</
  47. when :text
  48. 6 opts[:reject] = /^</
  49. 12 opts[:postprocess] = proc { |word| word.gsub("\n", "<br>") }
  50. when :pointer
  51. 3 opts[:preprocess] = proc { |word| word.gsub("[[", "").gsub("]]", "<br>") }
  52. else # :raw
  53. 65 opts[:preprocess] = proc { |word| CGI.escapeHTML(word) }
  54. end
  55. 33 opts
  56. end
  57. end
  58. end
  59. end

card/lib/card/content/diff/l_c_s.rb

97.96% lines covered

49 relevant lines. 48 lines covered and 1 lines missed.
    
  1. # require "card/content/diff/processor"
  2. 1 class Card
  3. 1 class Content
  4. 1 class Diff
  5. # Use LCS algorithm to create a {Diff::Result}
  6. 1 class LCS
  7. 1 def initialize opts
  8. # regex; remove matches completely from diff
  9. 33 @reject_pattern = opts[:reject]
  10. # regex; put matches back to the result after diff
  11. 33 @exclude_pattern = opts[:exclude]
  12. 33 @preprocess = opts[:preprocess] # block; called with every word
  13. 33 @postprocess = opts[:postprocess] # block; called with complete diff
  14. 33 @splitters = %w(<[^>]+> \[\[[^\]]+\]\] \{\{[^}]+\}\} \s+)
  15. 33 @disjunction_pattern = /^\s/
  16. end
  17. 1 def run old_text, new_text, result
  18. 33 @result = result
  19. 33 compare old_text, new_text
  20. 33 @result.complete = postprocess @result.complete
  21. end
  22. 1 private
  23. 1 def compare old_text, new_text
  24. 33 if old_text
  25. 27 old_words, old_ex = separate_comparables_from_excludees old_text
  26. 27 new_words, new_ex = separate_comparables_from_excludees new_text
  27. 27 processor = Processor.new old_words, new_words, old_ex, new_ex
  28. 27 processor.run @result
  29. else
  30. 6 list = split_and_preprocess(new_text)
  31. 6 list = list.reject { |word| word.match @exclude_pattern } if @exclude_pattern
  32. # CAUTION: postproces and added_chunk changed order
  33. # and no longer postprocess for summary
  34. 6 @result.write_added_chunk list.join
  35. end
  36. end
  37. 1 def separate_comparables_from_excludees text
  38. # return two arrays, one with all words, one with pairs
  39. # (index in word list, html_tag)
  40. 54 list = split_and_preprocess text
  41. 54 if @exclude_pattern
  42. 16 check_exclude_and_disjunction_pattern list
  43. else
  44. 38 [list, []]
  45. end
  46. end
  47. 1 def check_exclude_and_disjunction_pattern list
  48. 16 list.each_with_index.each_with_object([[], []]) do |pair, res|
  49. 103 element, index = pair
  50. 103 if element.match? @disjunction_pattern
  51. 32 res[1] << { chunk_index: index, element: element, type: :disjunction }
  52. 71 elsif element.match? @exclude_pattern
  53. 24 res[1] << { chunk_index: index, element: element, type: :excludee }
  54. else
  55. 47 res[0] << element
  56. end
  57. end
  58. end
  59. 1 def split_and_preprocess text
  60. 60 splitted = split_to_list_of_words(text).select do |s|
  61. 213 !s.empty? && (!@reject_pattern || !s.match(@reject_pattern))
  62. end
  63. 109 @preprocess ? splitted.map { |s| @preprocess.call(s) } : splitted
  64. end
  65. 1 def split_to_list_of_words text
  66. 60 split_regex = /(#{@splitters.join '|'})/
  67. 60 text.split(split_regex)
  68. end
  69. 1 def preprocess text
  70. @preprocess ? @preprocess.call(text) : text
  71. end
  72. 1 def postprocess text
  73. 33 @postprocess ? @postprocess.call(text) : text
  74. end
  75. end
  76. end
  77. end
  78. end

card/lib/card/content/diff/l_c_s/processor.rb

93.55% lines covered

93 relevant lines. 87 lines covered and 6 lines missed.
    
  1. 1 class Card
  2. 1 class Content
  3. 1 class Diff
  4. 1 class LCS
  5. # Compares two lists of chunks and generates a diff
  6. 1 class Processor
  7. 1 def initialize old_words, new_words, old_excludees, new_excludees
  8. 27 @adds = []
  9. 27 @dels = []
  10. 27 @words = { old: old_words, new: new_words }
  11. @excludees =
  12. 27 ExcludeeIterator.old_and_new old_excludees, new_excludees
  13. end
  14. 1 def run result
  15. 27 @result = result
  16. 27 prev_action = nil
  17. 27 ::Diff::LCS.traverse_balanced(@words[:old], @words[:new]) do |word|
  18. 62 process_word word, prev_action
  19. 62 prev_action = word.action
  20. end
  21. 27 write_all
  22. 27 @result
  23. end
  24. 1 def process_word word, prev_action
  25. 62 prev_action ? interpret_action(prev_action, word.action) : write_excludees
  26. 62 process_element word.old_element, word.new_element, word.action
  27. end
  28. 1 def interpret_action prev_actn, word_actn
  29. 35 handle_action?(word_actn, prev_actn) ? handle_action(word_actn) : write_all
  30. end
  31. 1 def handle_action? word_action, prev_action
  32. 35 (prev_action == word_action) ||
  33. 18 (prev_action == "-" && word_action == "!") ||
  34. 18 (prev_action == "!" && word_action == "+")
  35. end
  36. 1 def handle_action action
  37. 17 case action
  38. when "-" then del_old_excludees
  39. 11 when "+" then add_new_excludees
  40. when "!" then
  41. 2 del_old_excludees
  42. 2 add_new_excludees
  43. else
  44. 4 write_excludees
  45. end
  46. end
  47. 1 def write_all
  48. 45 write_dels
  49. 45 write_adds
  50. 45 write_excludees
  51. end
  52. 1 def write_unchanged text
  53. 19 @result.write_unchanged_chunk text
  54. end
  55. 1 def write_dels
  56. 45 return if @dels.empty?
  57. 24 @result.write_deleted_chunk @dels.join
  58. 24 @dels = []
  59. end
  60. 1 def write_adds
  61. 45 return if @adds.empty?
  62. 29 @result.write_added_chunk @adds.join
  63. 29 @adds = []
  64. end
  65. 1 def write_excludees
  66. 182 while (ex = @excludees[:new].next)
  67. 30 @result.write_excluded_chunk ex[:element]
  68. end
  69. end
  70. 1 def del_old_excludees
  71. 2 @excludees[:old].scan_and_record(@dels) do |element|
  72. write_dels
  73. @result.write_excluded_chunk element
  74. end
  75. end
  76. 1 def add_new_excludees
  77. 13 @excludees[:new].scan_and_record(@adds) do |element|
  78. write_adds
  79. @result.complete << element
  80. end
  81. end
  82. 1 def process_element old_element, new_element, action
  83. 62 case action
  84. 1 when "-" then minus old_element
  85. 17 when "+" then plus new_element
  86. when "!"
  87. 25 minus old_element
  88. 25 plus new_element
  89. else
  90. 19 write_unchanged new_element
  91. 19 @excludees[:new].word_step
  92. end
  93. end
  94. 1 def plus new_element
  95. 42 @adds << new_element
  96. 42 @excludees[:new].word_step
  97. end
  98. 1 def minus old_element
  99. 26 @dels << old_element
  100. 26 @excludees[:old].word_step
  101. end
  102. end
  103. # support class for LCS::Processor
  104. 1 class ExcludeeIterator
  105. 1 def self.old_and_new old_excludees, new_excludees
  106. {
  107. 27 old: new(old_excludees),
  108. new: new(new_excludees)
  109. }
  110. end
  111. 1 def initialize list
  112. 54 @list = list
  113. 54 @index = 0
  114. 54 @chunk_index = 0
  115. end
  116. 1 def word_step
  117. 87 @chunk_index += 1
  118. end
  119. 1 def next
  120. 123 if @index < @list.size &&
  121. @list[@index][:chunk_index] == @chunk_index
  122. 32 res = @list[@index]
  123. 32 @index += 1
  124. 32 @chunk_index += 1
  125. 32 res
  126. end
  127. end
  128. 1 def scan_and_record record_array
  129. 32 while (ex = self.next)
  130. 2 if ex[:type] == :disjunction
  131. 2 record_array << ex[:element]
  132. else
  133. yield ex[:element]
  134. end
  135. end
  136. end
  137. end
  138. end
  139. end
  140. end
  141. end

card/lib/card/content/diff/result.rb

91.49% lines covered

94 relevant lines. 86 lines covered and 8 lines missed.
    
  1. 1 class Card
  2. 1 class Content
  3. 1 class Diff
  4. # Result object for Diff processing
  5. 1 class Result
  6. 1 attr_accessor :complete, :summary, :dels_cnt, :adds_cnt
  7. 1 def initialize summary_opts=nil
  8. 33 @dels_cnt = 0
  9. 33 @adds_cnt = 0
  10. 33 @complete = ""
  11. 33 @summary = Summary.new summary_opts
  12. end
  13. 1 def summary
  14. 13 @summary.rendered
  15. end
  16. 1 def summary_omits_content?
  17. 5 @summary.omits_content?
  18. end
  19. 1 def write_added_chunk text
  20. 35 @adds_cnt += 1
  21. 35 @complete << Card::Content::Diff.render_added_chunk(text)
  22. 35 @summary.add text
  23. end
  24. 1 def write_deleted_chunk text
  25. 24 @dels_cnt += 1
  26. 24 @complete << Card::Content::Diff.render_deleted_chunk(text)
  27. 24 @summary.delete text
  28. end
  29. 1 def write_unchanged_chunk text
  30. 19 @complete << text
  31. 19 @summary.omit
  32. end
  33. 1 def write_excluded_chunk text
  34. 30 @complete << text
  35. end
  36. # Summary object for Diff processing
  37. 1 class Summary
  38. 1 def initialize opts
  39. 33 opts ||= {}
  40. 33 @remaining_chars = opts[:length] || 50
  41. 33 @joint = opts[:joint] || "..."
  42. 33 @summary = nil
  43. 33 @chunks = []
  44. 33 @content_omitted = false
  45. end
  46. 1 def rendered
  47. 13 @summary ||=
  48. begin
  49. 13 truncate_overlap
  50. 13 @chunks.map do |chunk|
  51. 30 @content_omitted ||= chunk[:action] == :ellipsis
  52. 30 render_chunk chunk[:action], chunk[:text]
  53. end.join
  54. end
  55. end
  56. 1 def add text
  57. 35 add_chunk text, :added
  58. end
  59. 1 def delete text
  60. 24 add_chunk text, :deleted
  61. end
  62. 1 def omit
  63. 19 if @chunks.empty? || @chunks.last[:action] != :ellipsis
  64. 15 add_chunk @joint, :ellipsis
  65. end
  66. end
  67. 1 def omits_content?
  68. 5 @content_omitted || @remaining_chars < 0
  69. end
  70. 1 private
  71. 1 def add_chunk text, action
  72. 74 if @remaining_chars > 0
  73. 71 @chunks << { action: action, text: text }
  74. 71 @remaining_chars -= text.size
  75. end
  76. end
  77. 1 def render_chunk action, text
  78. 30 case action
  79. when "+", :added
  80. 14 Card::Content::Diff.render_added_chunk text
  81. when "-", :deleted
  82. 11 Card::Content::Diff.render_deleted_chunk text
  83. 5 else text
  84. end
  85. end
  86. 1 def truncate_overlap
  87. 13 return unless @remaining_chars < 0
  88. 3 process_ellipsis
  89. 3 index = @chunks.size - 1
  90. 3 while @remaining_chars < @joint.size && index >= 0
  91. 3 overlap_size = @remaining_chars + @chunks[index][:text].size
  92. 3 break if process_overlap overlap_size, index
  93. index -= 1
  94. end
  95. end
  96. 1 def process_ellipsis
  97. 3 return unless @chunks.last[:action] == :ellipsis
  98. @chunks.pop
  99. @content_omitted = true
  100. @remaining_chars += @joint.size
  101. end
  102. 1 def process_overlap overlap_size, index
  103. 3 if overlap_size == @joint.size
  104. 1 replace_with_joint index
  105. 1 true
  106. 2 elsif overlap_size > @joint.size
  107. 2 cut_with_joint index
  108. 2 true
  109. else
  110. @remaining_chars += @chunks[index][:text].size
  111. @chunks.delete_at(index)
  112. false
  113. end
  114. end
  115. 1 def cut_with_joint index
  116. 2 @chunks[index][:text] =
  117. 2 @chunks[index][:text][0..(@remaining_chars - @joint.size - 1)]
  118. 2 @chunks[index][:text] += @joint
  119. end
  120. 1 def replace_with_joint index
  121. 1 @chunks.pop
  122. 1 if index - 1 >= 0
  123. 1 if @chunks[index - 1][:action] == :added
  124. @chunks << { action: :ellipsis, text: @joint }
  125. 1 elsif @chunks[index - 1][:action] == :deleted
  126. 1 @chunks << { action: :added, text: @joint }
  127. end
  128. end
  129. end
  130. end
  131. end
  132. end
  133. end
  134. end

card/lib/card/content/parser.rb

100.0% lines covered

49 relevant lines. 49 lines covered and 0 lines missed.
    
  1. # require "card/content/chunk"
  2. 1 class Card
  3. 1 class Content
  4. # The Content::Parser breaks content strings into an Array of "chunks",
  5. # each of which may be an instance of a {Chunk} class or a simple String.
  6. 1 class Parser
  7. # @param chunk_list [Symbol] name of registered list of chunk classes
  8. # to be used in parsing
  9. # @see Card::Chunk.register_list
  10. # @param content_object [Card::Content]
  11. 1 def initialize chunk_list, content_object
  12. 4237 @content_object = content_object
  13. 4237 @chunk_list = chunk_list
  14. end
  15. # break content string into an array of chunk objects and strings
  16. # @param content [String]
  17. # @return [Array]
  18. 1 def parse content
  19. 4237 @content = content
  20. 4237 @chunks = []
  21. 4237 return @chunks unless content.is_a? String
  22. 4237 @position = @last_position = 0
  23. 4237 @interval_string = ""
  24. 4237 parse_chunks
  25. 4237 @chunks
  26. end
  27. 1 private
  28. 1 def parse_chunks
  29. 4237 prefix_regexp = Chunk.prefix_regexp @chunk_list
  30. 4237 match_prefices prefix_regexp
  31. 4237 handle_remainder
  32. end
  33. 1 def match_prefices prefix_regexp
  34. 4237 while match_prefix prefix_regexp
  35. 6331 @chunk_class = Chunk.find_class_by_prefix @prefix, @chunk_list
  36. # get the chunk class from the prefix
  37. 6331 content_slice = @content[@position..-1]
  38. 6331 @match, @offset = @chunk_class.full_match content_slice, @prefix
  39. # see whether the full chunk actually matches
  40. # (as opposed to bogus prefix)
  41. 6331 if @match # we have a chunk match
  42. 6305 next if record_chunk
  43. else # no match. look at the next character
  44. 26 @position += 1
  45. end
  46. 32 @interval_string += @content[@chunk_start..@position - 1]
  47. # moving beyond the alleged chunk.
  48. # append failed string to "nonchunk" string
  49. end
  50. end
  51. 1 def match_prefix prefix_regexp
  52. 10568 prefix_match = @content[@position..-1].match(prefix_regexp)
  53. 10568 if prefix_match
  54. 6331 @prefix = prefix_match[0]
  55. # prefix of matched chunk
  56. 6331 @chunk_start = prefix_match.begin(0) + @position
  57. # content index of beginning of chunk
  58. 6331 if prefix_match.begin(0) > 0
  59. # if matched chunk is not beginning of test string
  60. 5006 @interval_string += @content[@position..@chunk_start - 1]
  61. # hold onto the non-chunk part of the string
  62. end
  63. 6331 @position = @chunk_start
  64. # move scanning position up to beginning of chunk
  65. 6331 true
  66. end
  67. end
  68. 1 def record_chunk
  69. 6305 @position += (@match.end(0) - @offset.to_i)
  70. # move scanning position up to end of chunk
  71. 6305 if !@chunk_class.context_ok? @content, @chunk_start
  72. # make sure there aren't contextual reasons for ignoring this chunk
  73. 6 false
  74. else
  75. 6299 @chunks << @interval_string unless @interval_string.empty?
  76. 6299 @interval_string = ""
  77. # add the nonchunk string to the chunk list and
  78. # reset interval string for next go-round
  79. 6299 @chunks << @chunk_class.new(@match, @content_object)
  80. # add the chunk to the chunk list
  81. 6299 @last_position = @position
  82. # note that the end of the chunk was the last place where a
  83. # chunk was found (so far)
  84. 6299 true
  85. end
  86. end
  87. 1 def handle_remainder
  88. 4237 if @chunks.any? && @last_position < @content.size
  89. # handle any leftover nonchunk string at the end of content
  90. 1089 @chunks << @content[@last_position..-1]
  91. end
  92. end
  93. end
  94. end
  95. end

card/lib/card/content/truncate.rb

26.32% lines covered

38 relevant lines. 10 lines covered and 28 lines missed.
    
  1. 1 class Card
  2. 1 class Content
  3. # tools for truncating content
  4. 1 module Truncate
  5. 1 ELLIPSES_HTML = '<span class="closed-content-ellipses">...</span>'.freeze
  6. 1 def smart_truncate input, words=25
  7. return if input.nil?
  8. truncated, wordstring = truncate input, words
  9. # nuke partial tags at end of snippet
  10. wordstring.gsub!(/(<[^\>]+)$/, "")
  11. wordstring = close_tags wordstring
  12. wordstring += ELLIPSES_HTML if truncated
  13. # wordstring += '...' if wordlist.length > l
  14. polish wordstring
  15. end
  16. 1 private
  17. 1 def truncate input, words
  18. wordlist = input.to_s.split
  19. l = words.to_i - 1
  20. l = 0 if l.negative?
  21. truncating = wordlist.length > l
  22. wordstring = truncating ? wordlist[0..l].join(" ") : input.to_s
  23. [truncating, wordstring]
  24. end
  25. 1 def close_tags wordstring
  26. tags = find_tags wordstring
  27. tags.each { |t| wordstring += "</#{t}>" }
  28. wordstring
  29. end
  30. 1 def polish wordstring
  31. wordstring.gsub! %r{<[/]?br[\s/]*>}, " "
  32. # Also a hack -- get rid of <br>'s -- they make line view ugly.
  33. wordstring.gsub! %r{<[/]?p[^>]*>}, " "
  34. ## Also a hack -- get rid of <br>'s -- they make line view ugly.
  35. wordstring
  36. end
  37. 1 def find_tags wordstring
  38. tags = []
  39. # match tags with or without self closing (ie. <foo />)
  40. wordstring.scan(%r{\<([^\>\s/]+)[^\>]*?\>}).each do |t|
  41. tags.unshift(t[0])
  42. end
  43. # match tags with self closing and mark them as closed
  44. wordstring.scan(%r{\<([^\>\s/]+)[^\>]*?/\>}).each do |t|
  45. next unless (x = tags.index(t[0]))
  46. tags.slice!(x)
  47. end
  48. # match close tags
  49. wordstring.scan(%r{\</([^\>\s/]+)[^\>]*?\>}).each do |t|
  50. next unless (x = tags.rindex(t[0]))
  51. tags.slice!(x)
  52. end
  53. tags
  54. end
  55. end
  56. end
  57. end

card/lib/card/director/subdirector_array.rb

100.0% lines covered

29 relevant lines. 29 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 class Director
  3. 1 class SubdirectorArray < Array
  4. 1 def self.initialize_with_subcards parent
  5. 2846 dir_array = new(parent)
  6. 2846 parent.card.subcards.each_card do |subcard|
  7. 172 dir_array.add subcard
  8. end
  9. 2846 dir_array
  10. end
  11. 1 def initialize parent
  12. 2846 @parent = parent
  13. 2846 super()
  14. end
  15. 1 def add card
  16. 2042 card = card.card if card.is_a? Director
  17. 2042 existing(card) || fetch_new(card)
  18. end
  19. 1 alias_method :delete_director, :delete
  20. 1 def delete card
  21. 3 if card.is_a? Director
  22. 1 delete_director card
  23. else
  24. 4 delete_if { |dir| dir.card == card }
  25. end
  26. end
  27. 1 private
  28. 1 def existing card
  29. 4035 find { |dir| dir.card == card }
  30. end
  31. 1 def fetch_new card
  32. 1422 Director.fetch(card, @parent).tap do |dir|
  33. 1422 update dir, card unless dir.main?
  34. end
  35. end
  36. 1 def update dir, card
  37. 1422 dir.replace_card card if dir.card != card
  38. 1422 dir.parent = @parent
  39. 1422 self << dir
  40. end
  41. end
  42. end
  43. end

card/lib/card/env/success.rb

90.22% lines covered

92 relevant lines. 83 lines covered and 9 lines missed.
    
  1. 1 class Card
  2. 1 module Env
  3. # Success objects
  4. 1 class Success
  5. 1 include Card::Env::Location
  6. 1 attr_accessor :redirect, :name, :name_context, :reload
  7. 1 attr_writer :params, :card
  8. 1 attr_reader :id
  9. 1 def initialize name_context=nil, success_args=nil
  10. 159 @name_context = name_context
  11. 159 @new_args = {}
  12. 159 @params = OpenStruct.new
  13. 159 self << normalize_success_args(success_args)
  14. end
  15. 1 def in_context name_context
  16. 13 self.name_context = name_context
  17. 13 self
  18. end
  19. 1 def normalize_success_args success_args
  20. 159 case success_args
  21. when nil
  22. 146 self.mark = "_self"
  23. 146 {}
  24. when ActionController::Parameters
  25. success_args.to_unsafe_h
  26. else
  27. 13 success_args
  28. end
  29. end
  30. 1 def << value
  31. 164 if value.is_a? Hash
  32. 154 apply value
  33. else
  34. 10 self.target = value
  35. end
  36. end
  37. 1 def reload?
  38. 13 @reload.to_s == "true"
  39. end
  40. # TODO: refactor to use cardish
  41. 1 def mark= value
  42. 159 case value
  43. 4 when Integer then @id = value
  44. 153 when String then @name = value
  45. 2 when Card then @card = value
  46. else
  47. self.target = value
  48. end
  49. end
  50. # @deprecated
  51. 1 def id= id
  52. # for backwards compatibility use mark here.
  53. # id was often used for the card name
  54. 4 self.mark = id
  55. end
  56. 1 def type= type
  57. @new_args[:type] = type
  58. end
  59. 1 def type_id= type_id
  60. @new_args[:type_id] = type_id.to_i
  61. end
  62. 1 def content= content
  63. @new_args[:content] = content
  64. end
  65. 1 def target= value
  66. 66 @id = @name = @card = nil
  67. 66 @target = process_target value
  68. end
  69. 1 def process_target value
  70. 72 case value
  71. 2 when "" then ""
  72. 57 when "*previous", :previous then :previous
  73. 2 when %r{^(http|/)} then value
  74. when /^REDIRECT:\s*(.+)/
  75. 6 @redirect = true
  76. 6 process_target Regexp.last_match(1)
  77. 5 else self.mark = value
  78. end
  79. end
  80. 1 def apply hash
  81. 155 hash.each_pair do |key, value|
  82. 21 self[key] = value
  83. end
  84. end
  85. 1 def card name_context=@name_context
  86. 225 if @card
  87. 15 @card
  88. 210 elsif @id
  89. 3 Card.fetch @id
  90. 207 elsif @name
  91. 76 Card.fetch @name.to_name.absolute(name_context), new: @new_args
  92. end
  93. end
  94. 1 def target name_context=@name_context
  95. 225 card(name_context) ||
  96. 131 (@target == :previous ? Card::Env.previous_location : @target) ||
  97. Card.fetch(name_context)
  98. end
  99. 1 def []= key, value
  100. 25 if respond_to? "#{key}="
  101. 12 send "#{key}=", value
  102. else
  103. 13 @params.send "#{key}=", value
  104. end
  105. end
  106. 1 def [] key
  107. 1 if respond_to? key.to_sym
  108. send key.to_sym
  109. else
  110. 1 @params.send key.to_sym
  111. end
  112. end
  113. 1 def flash message=nil
  114. 126 @params[:flash] ||= []
  115. 126 @params[:flash] << message if message
  116. 126 @params[:flash]
  117. end
  118. 1 def params
  119. 16 @params.marshal_dump
  120. end
  121. 1 def raw_params
  122. @params
  123. end
  124. 1 def to_url name_context=@name_context
  125. 11 case (target = target(name_context))
  126. when Card
  127. 7 target.format.path params
  128. else
  129. 4 target
  130. end
  131. end
  132. 1 def method_missing method, *args
  133. 4 case method
  134. when /^(\w+)=$/
  135. 3 self[Regexp.last_match(1).to_sym] = args[0]
  136. when /^(\w+)$/
  137. 1 self[Regexp.last_match(1).to_sym]
  138. else
  139. super
  140. end
  141. end
  142. 1 def session
  143. Card::Env.session
  144. end
  145. end
  146. end
  147. end

card/lib/card/error.rb

92.94% lines covered

85 relevant lines. 79 lines covered and 6 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 class Card
  3. # exceptions and errors.
  4. # (arguably most of these should be Card::Exception)
  5. 1 class Error < StandardError
  6. 1 cattr_accessor :current
  7. 1 class_attribute :status_code, :view
  8. 1 attr_writer :backtrace
  9. 1 self.view = :errors
  10. 1 self.status_code = 422
  11. 1 attr_accessor :card
  12. 1 def initialize message=nil
  13. 29 if message.is_a? Card
  14. 1 self.card = message
  15. 1 message = message_from_card
  16. end
  17. 29 super message
  18. end
  19. 1 def message_from_card
  20. 1 I18n.t :exception_for_card,
  21. scope: %i[lib card error], cardname: card.name, message: card_message_text
  22. end
  23. 1 def backtrace
  24. 184 @backtrace || super
  25. end
  26. 1 def report
  27. 7 Rails.logger.info "exception = #{self.class}: #{message}"
  28. 7 Rails.logger.debug backtrace.join("\n")
  29. end
  30. 1 def card_message_text
  31. card.errors.first&.message
  32. end
  33. # error attributable to code (as opposed to card configuration)
  34. 1 class ServerError < Error
  35. 1 def self.view
  36. debugger_on? ? :debug_server_error : :server_error
  37. end
  38. 1 def self.status_code
  39. # Errors with status code 900 are displayed as modal instead of inside
  40. # the "card-notice" div``
  41. debugger_on? ? 900 : 500
  42. end
  43. 1 def self.debugger_on?
  44. Card::Codename[:debugger] && Card[:debugger]&.content =~ /on/
  45. end
  46. 1 def report
  47. 2 super
  48. 2 card&.notable_exception_raised
  49. end
  50. end
  51. # error whose message can be shown to any user
  52. 1 class UserError < Error
  53. 1 cattr_accessor :user_error_classes
  54. 1 self.user_error_classes = [self,
  55. ActionController::BadRequest,
  56. ActionController::MissingFile,
  57. ActiveRecord::RecordNotFound,
  58. ActiveRecord::RecordInvalid]
  59. end
  60. # error in CQL query
  61. 1 class BadQuery < UserError
  62. end
  63. 1 class BadAddress < UserError
  64. 1 self.status_code = 404
  65. 1 self.view = :bad_address
  66. end
  67. # card not found
  68. 1 class NotFound < UserError
  69. 1 self.status_code = 404
  70. 1 self.view = :not_found
  71. end
  72. 1 class CodenameNotFound < NotFound
  73. end
  74. # two editors altering the same card at once
  75. 1 class EditConflict < UserError
  76. 1 self.status_code = 409
  77. 1 self.view = :conflict
  78. end
  79. # permission errors
  80. 1 class PermissionDenied < UserError
  81. 1 self.status_code = 403
  82. 1 self.view = :denial
  83. 1 def card_message_text
  84. 1 card.errors[:permission_denied]
  85. end
  86. end
  87. # exception class for aborting card actions
  88. 1 class Abort < StandardError
  89. 1 attr_reader :status
  90. 1 def report
  91. Rails.logger.debug "aborting: #{message}"
  92. end
  93. 1 def initialize status, msg=""
  94. 99 @status = status
  95. 99 super msg
  96. end
  97. end
  98. # associating views with exceptions
  99. 1 class << self
  100. 1 KEY_MAP = { permission_denied: PermissionDenied,
  101. conflict: EditConflict }.freeze
  102. 1 def report exception, card
  103. 7 e = cardify_exception exception, card
  104. 7 self.current = e
  105. 7 e.report
  106. 7 e
  107. end
  108. 1 def cardify_exception exception, card
  109. card_exception =
  110. 7 if exception.is_a? Card::Error
  111. 2 exception
  112. else
  113. 5 card_error_class(exception, card).new exception.message
  114. end
  115. 7 card_exception.card ||= card
  116. 7 card_exception.backtrace ||= exception.backtrace
  117. 7 add_card_errors card, card_exception if card.errors.empty?
  118. 7 card_exception
  119. end
  120. 1 def add_card_errors card, exception
  121. 4 label = exception.class.to_s.split("::").last
  122. 4 card.errors.add label, exception.message
  123. end
  124. 1 def card_error_class exception, card
  125. # "simple" error messages are visible to end users and are generally not
  126. # treated as software bugs (though they may be "shark" bugs)
  127. 5 case exception
  128. when ActiveRecord::RecordInvalid
  129. 3 invalid_card_error_class card
  130. when ActiveRecord::RecordNotFound, ActionController::MissingFile
  131. Card::Error::NotFound
  132. else
  133. 2 Card::Error::ServerError
  134. end
  135. end
  136. 1 def invalid_card_error_class card
  137. 3 KEY_MAP.each do |key, klass|
  138. 5 return klass if card.errors.key? key
  139. end
  140. 2 Card::Error
  141. end
  142. end
  143. end
  144. end

card/lib/card/format/nest.rb

100.0% lines covered

39 relevant lines. 39 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 class Format
  3. # processing nests
  4. 1 class Nest
  5. 1 include Fetch
  6. 1 attr_accessor :format, :card, :view, :view_opts, :format_opts
  7. 1 def initialize format, cardish, view_opts={}, format_opts={}
  8. 7930 @format = format
  9. 7930 @view_opts = view_opts
  10. 7930 @format_opts = format_opts.clone
  11. 7930 @override = @format_opts.delete(:override) != false
  12. 7930 @card ||= fetch_card cardish
  13. # note: fetch_card can alter view and view_opts[:nest_name]
  14. end
  15. 1 def prepare
  16. 7930 prepare_view_and_opts!
  17. 7930 subformat = prepare_subformat
  18. 7930 @view = subformat.modal_nest_view @view if @override
  19. 7930 yield subformat, view
  20. end
  21. 1 private
  22. 1 def prepare_view_and_opts!
  23. 7930 view_opts[:nest_name] ||= card.name
  24. 7930 @view ||= prepare_view
  25. # TODO: handle in closed / edit view definitions
  26. 7930 view_opts[:home_view] ||= %i[closed edit].member?(view) ? :open : view
  27. end
  28. 1 def prepare_view
  29. 7929 view = view_opts[:view] || format.implicit_nest_view
  30. # TODO: canonicalize view and modal_nest_view handling should be in Card::View,
  31. # not here. (Make sure processing only happens on nests/root views)
  32. 7929 Card::View.normalize view
  33. end
  34. # @return [Format] subformat object
  35. 1 def prepare_subformat
  36. 7930 return format if reuse_format?
  37. 7926 sub = format.subformat card, format_opts
  38. 7926 sub.main! if view_opts[:main]
  39. 7926 sub
  40. end
  41. # sometimes we use the same format (rather than a new subformat)
  42. # when nesting the same card. this reduces overhead and optimizes
  43. # caching
  44. 1 def reuse_format?
  45. 7930 self_nest? && !nest_recursion_risk?
  46. end
  47. 1 def self_nest?
  48. 7930 self_nest = view_opts[:nest_name] =~ /^_(self)?$/ &&
  49. format.context_card == format.card
  50. # self nest in focal format should add depth (to catch recursions) but
  51. # remain focal
  52. 7930 format_opts[:focal] = true if self_nest && format.focal?
  53. 7930 self_nest
  54. end
  55. # don't reuse the format when there is a risk of recursion, because while nest
  56. # recursion is caught, view recursion is not.
  57. # TODO: catch view recursion and remove this. (Should be straightforward within voo)
  58. 1 def nest_recursion_risk?
  59. 24 content_view? || format.voo&.structure
  60. end
  61. 1 def content_view?
  62. # TODO: this should be specified in view definition
  63. 24 %i[
  64. bar expanded_bar core content titled open closed open_content one_line_content
  65. ].member? @view.to_sym
  66. end
  67. end
  68. end
  69. end

card/lib/card/format/nest/fetch.rb

100.0% lines covered

41 relevant lines. 41 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 class Format
  3. 1 class Nest
  4. # Fetch card for a nest
  5. 1 module Fetch
  6. 1 private
  7. 1 def fetch_card cardish
  8. 7930 case cardish
  9. 5489 when Card then cardish
  10. 100 when Symbol, Integer then Card.fetch cardish
  11. 1015 when "_", "_self" then format.context_card
  12. 1326 else new_card cardish
  13. end
  14. rescue Card::Error::CodenameNotFound
  15. 1 not_found_codename cardish
  16. end
  17. 1 def not_found_codename cardish
  18. 1 @view = :not_found
  19. 1 c = Card.new name: Array.wrap(cardish).join(Card::Name.joint).to_s
  20. 1 c.errors.add :codename, not_found_codename_error(cardish)
  21. 1 c
  22. end
  23. 1 def not_found_codename_error codename
  24. 1 ::I18n.t :exception_unknown_codename, codename: codename,
  25. scope: "lib.card.codename"
  26. end
  27. 1 def new_card cardish
  28. 1326 view_opts[:nest_name] = Card::Name[cardish].to_s
  29. 1326 Card.fetch cardish, new: new_card_args
  30. end
  31. 1 def new_card_args
  32. 1326 args = { name: view_opts[:nest_name] }
  33. 1326 args[:type] = view_opts[:type] if view_opts[:type]
  34. 1326 args.merge(new_supercard_args)
  35. .merge(new_main_args)
  36. .merge(new_content_args)
  37. end
  38. 1 def new_supercard_args
  39. # special case. gets absolutized incorrectly. fix in name?
  40. 1326 return {} if view_opts[:nest_name].strip.blank?
  41. 1322 { supercard: format.context_card }
  42. end
  43. 1 def new_main_args
  44. 1326 nest_name = view_opts[:nest_name]
  45. 1326 return {} unless nest_name =~ /main/
  46. 31 { name: nest_name.gsub(/^_main\+/, "+"),
  47. supercard: format.root.card }
  48. end
  49. 1 def new_content_args
  50. 1326 content = content_from_shorthand_param || content_from_subcard_params
  51. 1326 content ? { content: content } : {}
  52. end
  53. 1 def content_from_shorthand_param
  54. # FIXME: this is a lame shorthand; could be another card's key
  55. # should be more robust and managed by Card::Name
  56. 1326 shorthand_param = view_opts[:nest_name].tr "+", "_"
  57. 1326 Env.params[shorthand_param]
  58. end
  59. 1 def content_from_subcard_params
  60. 1326 Env.params.dig "subcards", view_opts[:nest_name], "content"
  61. end
  62. end
  63. end
  64. end
  65. end

card/lib/card/mailer.rb

100.0% lines covered

18 relevant lines. 18 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 require "open-uri"
  3. 1 class Card
  4. 1 class Mailer < ActionMailer::Base
  5. 1 @@defaults = Card.config.email_defaults || {}
  6. 1 @@defaults.symbolize_keys!
  7. 1 @@defaults[:return_path] ||= @@defaults[:from] if @@defaults[:from]
  8. 1 @@defaults[:charset] ||= "utf-8"
  9. 1 default @@defaults
  10. 1 class << self
  11. 1 def new_mail *args, &block
  12. 102 mail = Mail.new(args, &block)
  13. 102 method = Card::Mailer.delivery_method
  14. 102 mail.delivery_method(method, Card::Mailer.send(:"#{method}_settings"))
  15. 102 mail.perform_deliveries = Card::Mailer.perform_deliveries
  16. 102 mail.raise_delivery_errors = Card::Mailer.raise_delivery_errors
  17. 102 mail
  18. end
  19. 1 def layout message
  20. 103 <<-HTML
  21. <!DOCTYPE html>
  22. <html>
  23. <head>
  24. <meta http-equiv="Content-type" content="text/html;charset=UTF-8"/>
  25. </head>
  26. <body>
  27. #{message}
  28. </body>
  29. </html>
  30. HTML
  31. end
  32. end
  33. end
  34. end

card/lib/card/migration.rb

37.04% lines covered

81 relevant lines. 30 lines covered and 51 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 class Card
  3. 1 class Migration < ActiveRecord::Migration[4.2]
  4. 1 include Card::Model::SaveHelper
  5. 1 @type = :deck_cards
  6. 1 class << self
  7. # Rake tasks use class methods, migrations use instance methods.
  8. # To avoid repetition a lot of instance methods here just call class
  9. # methods.
  10. # The subclass Card::CoreMigration needs a different @type so we can't use a
  11. # class variable @@type. It has to be a class instance variable.
  12. # Migrations are subclasses of Card::Migration or Card::CoreMigration
  13. # but they don't inherit the @type. The method below solves this problem.
  14. 1 def type
  15. 7 @type || (ancestors[1]&.type)
  16. end
  17. 1 def find_unused_name base_name
  18. test_name = base_name
  19. add = 1
  20. while Card.exists?(test_name)
  21. test_name = "#{base_name}#{add}"
  22. add += 1
  23. end
  24. test_name
  25. end
  26. 1 def migration_paths mig_type=type
  27. 7 Cardio.migration_paths mig_type
  28. end
  29. 1 def schema mig_type=type
  30. Cardio.schema mig_type
  31. end
  32. 1 def schema_suffix mig_type=type
  33. Cardio.schema_suffix mig_type
  34. end
  35. 1 def schema_mode mig_type=type
  36. Cardio.with_suffix mig_type do
  37. paths = Cardio.migration_paths(type)
  38. yield(paths)
  39. end
  40. end
  41. 1 def assume_migrated_upto_version
  42. schema_mode do
  43. ActiveRecord::Schema.assume_migrated_upto_version schema,
  44. migration_paths
  45. end
  46. end
  47. 1 def data_path filename=nil
  48. 7 path = migration_paths.first
  49. 7 File.join([path, "data", filename].compact)
  50. end
  51. end
  52. 1 def contentedly
  53. Card::Cache.reset_all
  54. Cardio.schema_mode "" do
  55. Card::Auth.as_bot do
  56. yield
  57. ensure
  58. ::Card::Cache.reset_all
  59. end
  60. end
  61. end
  62. # def disable_ddl_transaction #:nodoc:
  63. # true
  64. # end
  65. 1 def import_json filename, merge_opts={}
  66. Card::Mailer.perform_deliveries = false
  67. output_file = File.join data_path, "unmerged_#{filename}"
  68. merge_opts[:output_file] ||= output_file
  69. Card.merge_list read_json(filename), merge_opts
  70. end
  71. 1 def import_cards filename, merge_opts={}
  72. Card::Mailer.perform_deliveries = false
  73. output_file = File.join data_path, "unmerged_#{filename}"
  74. merge_opts[:output_file] ||= output_file
  75. meta_data = JSON.parse(File.read(data_path(filename)))
  76. full_data =
  77. meta_data.map do |hash|
  78. hash["content"] =
  79. File.read data_path(File.join("cards", hash["name"].to_name.key))
  80. hash
  81. end
  82. Card.merge_list full_data, merge_opts
  83. end
  84. # uses the data in cards.yml and the card content in db/migrate_cards/data/cards
  85. # to update or create the cards given by name or key in names_or_keys
  86. 1 def merge_cards names_or_keys
  87. names_or_keys = Array(names_or_keys)
  88. Card::Mailer.perform_deliveries = false
  89. Card::Migration::Import.new(data_path).merge only: names_or_keys
  90. end
  91. 1 def merge_pristine_cards names_or_keys
  92. names_or_keys = Array(names_or_keys)
  93. pristine = names_or_keys.select { |n| !Card.exists?(n) || Card.fetch(n)&.pristine? }
  94. merge_cards pristine
  95. end
  96. 1 def read_json filename
  97. raw_json = File.read data_path(filename)
  98. json = JSON.parse raw_json
  99. json.is_a?(Hash) ? json["card"]["value"] : json
  100. end
  101. 1 def data_path filename=nil
  102. self.class.data_path filename
  103. end
  104. 1 def schema_mode
  105. Cardio.schema_mode self.class.type
  106. end
  107. 1 def migration_paths
  108. Cardio.paths self.class.type
  109. end
  110. # Execute this migration in the named direction
  111. # copied from ActiveRecord to wrap 'up' in 'contentendly'
  112. 1 def exec_migration conn, direction
  113. @connection = conn
  114. if respond_to?(:change)
  115. if direction == :down
  116. revert { change }
  117. else
  118. change
  119. end
  120. else
  121. contentedly { send(direction) }
  122. end
  123. ensure
  124. @connection = nil
  125. end
  126. 1 def down
  127. raise ActiveRecord::IrreversibleMigration
  128. end
  129. 1 def update_machine_output
  130. Card.search(right: { codename: "machine_output" }).each(&:delete)
  131. end
  132. end
  133. end
  134. 1 require "card/migration/core"

card/lib/card/migration/core.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 require "card/migration"
  3. 1 class Card
  4. 1 class Migration
  5. 1 class Core < Migration
  6. 1 @type = :core_cards
  7. end
  8. end
  9. end

card/lib/card/migration/import.rb

71.43% lines covered

49 relevant lines. 35 lines covered and 14 lines missed.
    
  1. 1 require_relative "import/import_data"
  2. 1 require_relative "import/merger"
  3. 1 class Card
  4. 1 class Migration
  5. # Imports card data from a local or remote deck
  6. #
  7. # The cards' content for the import is stored for every card in a separate
  8. # file, other attributes like name or type are stored for all cards together
  9. # in a yml file.
  10. #
  11. # To update a card's content you only have to change the card's content
  12. # file. The merge method will recognize that the file was changed
  13. # since the last merge and merge it into the cards table
  14. # To update other attributes change them in the yml file and either remove
  15. # the 'merged' value or touch the corresponding content file
  16. 1 class Import
  17. 1 def initialize data_path
  18. 7 @data_path = data_path
  19. end
  20. # Merge the import data into the cards table.
  21. # Bu default it merges only the data that was changed or added
  22. # since the last merge.
  23. # @param [Hash] opts choose which cards to merge
  24. # @option opts [Boolean] :all merge all available import data
  25. # @option opts [Array] :only a key/name or list of keys/names to
  26. # be merged
  27. 1 def merge opts={}
  28. 1 Merger.new(@data_path, opts).merge
  29. end
  30. # Get import data from a deck
  31. # @param [String] name The name of the card to be imported
  32. # @param [Hash] opts pull options
  33. # @option opts [String] remote Use a remote url. The remote url must
  34. # have been registered via 'add_remote'
  35. # @option opts [Boolean] deep if true fetch all nested cards, too
  36. # @option opts [Boolean] items_only if true fetch all nested cards but
  37. # not the card itself
  38. 1 def pull name, opts={}
  39. 6 update do |import_data|
  40. 6 url = opts[:remote] ? import_data.url(opts.delete(:remote)) : nil
  41. 6 fetch_card_data(name, url, opts).each do |card_data|
  42. 9 import_data.add_card card_data
  43. end
  44. end
  45. end
  46. # Add a card with the given attributes to the import data
  47. 1 def add_card attr
  48. update do |data|
  49. data.add_card attr
  50. end
  51. end
  52. # Save an url as remote deck to make it available for the pull method
  53. 1 def add_remote name, url
  54. 1 update do |data|
  55. 1 data.add_remote name, url
  56. end
  57. end
  58. 1 private
  59. 1 def update &block
  60. 7 ImportData.update(@data_path, &block)
  61. end
  62. 1 def importer
  63. @importer ||= ImportData.new(@data_path)
  64. end
  65. # Returns an array of hashes with card attributes
  66. 1 def fetch_card_data name, url, opts
  67. view, result_key =
  68. 6 if opts[:items_only]
  69. ["export_items", nil]
  70. 6 elsif opts[:deep]
  71. 3 ["export", nil]
  72. else
  73. 3 [nil, :card]
  74. end
  75. card_data =
  76. 6 if url
  77. fetch_remote_data name, view, url
  78. else
  79. 6 fetch_local_data name, view
  80. end
  81. 6 result_key ? [card_data[result_key]] : card_data
  82. end
  83. 1 def fetch_remote_data name, view, url
  84. json_url = "#{url}/#{name}.json"
  85. json_url += "?view=#{view}" if view
  86. json = ::File.open(json_url).read
  87. parse_and_symbolize json
  88. end
  89. 1 def fetch_local_data name, view
  90. 6 Card::Auth.as_bot do
  91. 6 Card[name].format(format: :json).render!(view || :page)
  92. end
  93. end
  94. 1 def parse_and_symbolize json
  95. parsed = JSON.parse(json)
  96. case parsed
  97. when Hash then
  98. parsed.deep_symbolize_keys
  99. when Array then
  100. parsed.map(&:deep_symbolize_keys)
  101. else
  102. parsed
  103. end
  104. end
  105. end
  106. end
  107. end

card/lib/card/migration/import/import_data.rb

84.62% lines covered

65 relevant lines. 55 lines covered and 10 lines missed.
    
  1. 1 class Card
  2. 1 class Migration
  3. 1 class Import
  4. # Handles the card attributes and remotes for the import
  5. 1 class ImportData
  6. 1 include CardContent
  7. 1 include CardAttributes
  8. # Takes a block to update import data
  9. # use #add_card and #add_remote in the block to make
  10. # changes
  11. 1 def self.update data_path
  12. 8 data = ImportData.new(data_path)
  13. 8 yield(data)
  14. 8 data.write_attributes
  15. end
  16. 1 def self.load data_path, opts={}
  17. 1 data = ImportData.new(data_path)
  18. 1 if opts[:all]
  19. data.all_cards
  20. 1 elsif opts[:only]
  21. data.select_cards opts[:only]
  22. else
  23. 1 data.changed_cards
  24. end
  25. end
  26. 1 def initialize data_path
  27. 43 @path = File.join data_path, "cards.yml"
  28. 43 @card_content_dir = File.join data_path, "cards"
  29. 43 @data = read_attributes
  30. end
  31. 1 def all_cards
  32. cards.map { |data| prepare_for_import data }
  33. end
  34. 1 def select_cards names_or_keys
  35. names_or_keys.map do |key|
  36. attributes = find_card_attributes(key)
  37. unless attributes
  38. raise("no entry for #{key} (key: #{key.to_name.key}) in #{@path}")
  39. end
  40. prepare_for_import attributes
  41. end
  42. end
  43. 1 def changed_cards
  44. 1 cards.map do |data|
  45. 1 next unless changed?(data)
  46. 1 prepare_for_import data
  47. end.compact
  48. end
  49. # mark as merged
  50. 1 def merged data, time
  51. 1 update_attribute data["name"], :merged, time
  52. end
  53. # to be used in an update block
  54. 1 def add_card card_data
  55. 9 card_attr, card_content = split_attributes_and_content card_data
  56. 9 update_card_attributes card_attr
  57. 9 write_card_content card_attr, card_content
  58. 9 card_attr
  59. end
  60. # to be used in an update block
  61. 1 def add_remote name, url
  62. 1 remotes[name] = url
  63. end
  64. 1 def url remote_name
  65. remotes[remote_name.to_sym] || raise("unknown remote: #{remote_name}")
  66. end
  67. 1 private
  68. 1 def split_attributes_and_content data
  69. 9 card_data = {}
  70. 9 %i[name type codename].each do |key|
  71. 27 card_data[key] = data[key] if data[key]
  72. end
  73. 9 card_data[:key] = data[:name].to_name.key
  74. 9 [card_data, data[:content]]
  75. end
  76. 1 def remotes
  77. 1 @data[:remotes]
  78. end
  79. 1 def cards
  80. 20 @data[:cards]
  81. end
  82. 1 def prepare_for_import data
  83. 1 hash = card_attributes(data)
  84. 1 hash[:content] = card_content(data)
  85. 1 %i[file image].each do |attach|
  86. 2 hash[attach] &&= card_attachment(attach, data)
  87. end
  88. 1 hash.with_indifferent_access
  89. end
  90. 1 def changed? data
  91. 1 !data[:merged] || content_changed?(data)
  92. end
  93. 1 def card_attachment attach_type, data
  94. Card::Migration.data_path "files/#{data[attach_type]}"
  95. end
  96. end
  97. end
  98. end
  99. end

card/lib/card/migration/import/import_data/card_attributes.rb

88.57% lines covered

35 relevant lines. 31 lines covered and 4 lines missed.
    
  1. 1 class Card
  2. 1 class Migration
  3. 1 class Import
  4. 1 class ImportData
  5. # handles card attributes for import
  6. 1 module CardAttributes
  7. 1 def card_attributes data
  8. 1 card_attr = ::Set.new %i[name type codename file image]
  9. 4 data.select { |k, v| v && card_attr.include?(k) }
  10. end
  11. 1 def update_card_attributes card_data
  12. 9 card_entry = find_card_attributes card_data[:name]
  13. # we only want strings and not the whole name objects
  14. # for name and type
  15. 9 card_data[:name] = card_data[:name].to_s
  16. 9 card_data[:type] = card_data[:type].to_s
  17. 9 if card_entry
  18. card_entry.replace card_data
  19. else
  20. 9 cards << card_data
  21. end
  22. end
  23. 1 def update_attribute name, attr_key, attr_value
  24. 1 card = find_card_attributes name
  25. 1 return unless card
  26. card[attr_key] = attr_value
  27. card
  28. end
  29. 1 def write_attributes
  30. 8 File.write @path, @data.to_yaml
  31. rescue SystemCallError
  32. false
  33. # card.yml not written
  34. end
  35. 1 def read_attributes
  36. 43 ensure_path
  37. 43 return { cards: [], remotes: {} } unless File.exist? @path
  38. 23 YAML.load_file(@path).deep_symbolize_keys
  39. end
  40. 1 def find_card_attributes name
  41. 10 key = name.to_name.key
  42. 10 cards.find do |attr|
  43. 5 key == (attr[:key].present? ? attr[:key] : attr[:name].to_name.key)
  44. end
  45. end
  46. 1 private
  47. 1 def ensure_path
  48. 43 dir = File.dirname(@path)
  49. 43 FileUtils.mkpath dir unless Dir.exist? dir
  50. end
  51. end
  52. end
  53. end
  54. end
  55. end

card/lib/card/migration/import/import_data/card_content.rb

93.75% lines covered

16 relevant lines. 15 lines covered and 1 lines missed.
    
  1. 1 class Card
  2. 1 class Migration
  3. 1 class Import
  4. 1 class ImportData
  5. # handles card content for import
  6. 1 module CardContent
  7. 1 def card_content data
  8. 1 File.read(content_path(data))
  9. end
  10. 1 def content_changed? data
  11. Time.parse(data[:merged]) < File.mtime(content_path(data))
  12. end
  13. 1 private
  14. 1 def write_card_content data, content
  15. 9 FileUtils.mkpath @card_content_dir unless Dir.exist? @card_content_dir
  16. 9 File.write content_path(data), content.to_s
  17. end
  18. 1 def content_path data
  19. 10 filename = (data[:key] || data[:name]).to_name.safe_key
  20. 10 File.join @card_content_dir, filename
  21. end
  22. end
  23. end
  24. end
  25. end
  26. end

card/lib/card/migration/import/merger.rb

100.0% lines covered

20 relevant lines. 20 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 class Migration
  3. 1 class Import
  4. # executes the card import
  5. 1 class Merger
  6. 1 def initialize data_path, opts={}
  7. 1 @data_path = data_path
  8. 1 @output_path = File.join data_path, "unmerged"
  9. 1 @data = ImportData.load @data_path, opts
  10. end
  11. 1 def merge
  12. 1 puts("nothing to merge") && return if @data.empty?
  13. 1 Card::Mailer.perform_deliveries = false
  14. 1 Card::Auth.as_bot do
  15. 1 Card.merge_list @data, output_file: @output_path
  16. end
  17. 1 update_import_data
  18. end
  19. 1 private
  20. 1 def update_import_data
  21. 1 update_time = Time.zone.now.to_s
  22. 1 ImportData.update(@data_path) do |import_data|
  23. 1 @data.each do |card_data|
  24. 1 import_data.merged card_data, update_time
  25. end
  26. end
  27. end
  28. end
  29. end
  30. end
  31. end

card/lib/card/mod/load_strategy/eval.rb

100.0% lines covered

8 relevant lines. 8 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 module Mod
  3. 1 class LoadStrategy
  4. # Put everything for the module definition in one string and the evaluate
  5. # it immediately with ruby's eval method.
  6. 1 class Eval < LoadStrategy
  7. 1 def load_modules
  8. 2 each_file do |abs_path, module_names|
  9. 258 template = module_template.new module_names, abs_path, self
  10. 258 template.build
  11. end
  12. end
  13. end
  14. end
  15. end
  16. end

card/lib/card/query.rb

100.0% lines covered

23 relevant lines. 23 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 class Card
  3. # Card::Query is for finding implicit lists (or counts of lists) of cards.
  4. #
  5. # Search and Set cards use Card::Query to query the database, and it's also
  6. # frequently used directly in code.
  7. #
  8. # Query "statements" (objects, really) are made in CQL (Card Query
  9. # Language). Because CQL is used by Sharks, the primary language
  10. # documentation is on decko.org. (https://decko.org/CQL_Syntax). Note that the
  11. # examples there are in JSON, like Search card content, but statements in
  12. # Card::Query are in ruby form.
  13. #
  14. # In Decko's current form, Card::Query generates and executes SQL statements.
  15. # However, the SQL generation is largely (not yet fully) separated from the
  16. # CQL statement interpretation.
  17. #
  18. # The most common way to use Card::Query is as follows:
  19. # list_of_cards = Card::Query.run(statement)
  20. #
  21. # This is equivalent to:
  22. # query = Card::Query.new(statement)
  23. # list_of_cards = query.run
  24. #
  25. # Upon initiation, the query is interpreted, and the following key objects
  26. # are populated:
  27. #
  28. # - @join - an Array of Card::Query::Join objects
  29. # - @conditions - an Array of conditions
  30. # - @mod - a Hash of other query-altering keys
  31. # - @subqueries - a list of other queries nested within this one
  32. #
  33. # Each condition is either a SQL-ready string (boo) or an Array in this form:
  34. # [ field_string_or_sym, Card::Value::Query object ]
  35. 1 module Query
  36. 1 require "card/query/clause"
  37. 1 require "card/query/card_query"
  38. 1 require "card/query/sql_statement"
  39. # Card::Query::CardQuery
  40. # After conversion, ATTRIBUTES is a Hash where the key is the attribute
  41. # and the value is the attribute type:
  42. # { id: :basic, name: :basic, key: :basic ...}
  43. # This is used for rapid attribute type lookups in the interpretation phase.
  44. ATTRIBUTES = {
  45. # Each of the "basic" fields corresponds directly to a database field.
  46. # their values are translated fairly directly into SQL-safe values.
  47. # (These are referred to as "properties" in CQL documentation. Need to
  48. # reconcile #EFM)
  49. 1 basic: %i[id name key type_id content left_id right_id
  50. creator_id updater_id codename read_rule_id],
  51. # "Relational" values can involve tying multiple queries together
  52. relational: %i[type
  53. part left right
  54. editor_of edited_by last_editor_of last_edited_by
  55. creator_of created_by
  56. updater_of updated_by
  57. link_to linked_to_by
  58. include included_by
  59. nest nested_by
  60. refer_to referred_to_by
  61. member_of member
  62. found_by
  63. not sort match name_match complete],
  64. plus_relational: %i[plus left_plus right_plus],
  65. conjunction: %i[and or all any],
  66. ignore: %i[prepend append vars],
  67. deprecated: %i[view params size]
  68. }.each_with_object({}) do |pair, h|
  69. 58 pair[1].each { |v| h[v] = pair[0] }
  70. end
  71. 1 CONJUNCTIONS = { any: :or, in: :or, or: :or, all: :and, and: :and }.freeze
  72. 1 MODIFIERS = %i[conj return sort sort_as group dir limit offset]
  73. 8 .each_with_object({}) { |v, h| h[v] = nil }
  74. OPERATORS =
  75. 9 %w[!= = =~ < > in ~ is].each_with_object({}) { |v, h| h[v] = v }.merge(
  76. { eq: "=", gt: ">", lt: "<", match: "~", ne: "!=",
  77. "not in": "not in", "is not": "is not", "!": "is not" }.stringify_keys
  78. )
  79. 1 DEFAULT_ORDER_DIRS = { update: "desc", relevance: "desc" }.freeze
  80. 1 class << self
  81. 1 def new statement, comment=nil
  82. 4597 Query::CardQuery.new statement, comment
  83. end
  84. 1 def run statement, comment=nil
  85. 4209 new(statement, comment).run
  86. end
  87. 1 def class_for type
  88. 4007 const_get "#{type.capitalize}Query"
  89. end
  90. 1 def safe_sql txt
  91. 5063 txt = txt.to_s
  92. 5063 raise "CQL contains disallowed characters: #{txt}" if txt.match?(/[^\w\s*().,]/)
  93. 5063 txt
  94. end
  95. end
  96. end
  97. end

card/lib/card/query/abstract_query.rb

100.0% lines covered

48 relevant lines. 48 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. # superclass for CardQuery, ReferenceQuery, ActQuery, and ActionQuery
  4. #
  5. # Each of the Query classes handle interpretation of hash "statements"
  6. # into a number of objects known to the SqlStatement class, including
  7. # @conditions, @joins, @comment, and the catch-all @mods
  8. #
  9. # Sql queries involving multiple tables are made possible by the query
  10. # hierarchy as tracked by subqueries (children) and superqueries (parents).
  11. # For example, if one card links to another, then this can be represented
  12. # as a CardQuery with a ReferenceQuery child that in turn has another
  13. # CardQuery as its child.
  14. #
  15. # See AbstractQuery::Tie for more on how tables can be connected.
  16. 1 class AbstractQuery
  17. 1 include QueryHelper
  18. 1 include Tie
  19. 1 attr_reader :statement, :mods, :conditions, :vars,
  20. :subqueries, :superquery, :comment, :negate
  21. 1 attr_accessor :joins, :conditions_on_join
  22. 1 def initialize statement, _comment=nil
  23. 8602 @subqueries = []
  24. 8602 @conditions = []
  25. 8602 @joins = []
  26. 8602 @mods = {}
  27. 8602 @statement = statement.clone
  28. 8602 init_instance_vars :context, :superquery, :fasten, :negate
  29. 8602 @vars = init_query_vars
  30. 8602 table_alias
  31. end
  32. 1 def init_instance_vars *varnames
  33. 8602 varnames.each do |varname|
  34. 34408 instance_variable_set "@#{varname}", (@statement.delete(varname) || nil)
  35. end
  36. end
  37. 1 def init_query_vars
  38. 8602 if (v = @statement.delete :vars) then v.symbolize_keys
  39. 8599 elsif @superquery then @superquery.vars
  40. 4388 else {}
  41. end
  42. end
  43. 1 def interpret hash
  44. 2941 hash.each do |action, card|
  45. 2941 send action, card
  46. end
  47. end
  48. 1 def full?
  49. 140 false
  50. end
  51. 1 def sql
  52. 4514 @sql ||= Query::SqlStatement.new(self).build.to_s
  53. end
  54. 1 def root
  55. 28725 @root ||= @superquery ? @superquery.root : self
  56. end
  57. 1 def root?
  58. 20677 root == self
  59. end
  60. 1 def subquery opts={}
  61. 4209 klass = opts.delete(:class) || Query
  62. 4209 subquery = klass.new opts.merge(superquery: self)
  63. 4209 @subqueries << subquery
  64. 4209 subquery
  65. end
  66. 1 def context
  67. 250 if !@context.nil?
  68. 233 @context
  69. else
  70. 17 @context = superquery ? superquery.context : ""
  71. end
  72. end
  73. 1 def depth
  74. 8666 @depth ||= case
  75. 4384 when !superquery then 0
  76. 14 when fasten == :direct then superquery.depth
  77. 130 else superquery.depth + 1
  78. end
  79. end
  80. end
  81. end
  82. end

card/lib/card/query/abstract_query/query_helper.rb

100.0% lines covered

30 relevant lines. 30 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. 1 class AbstractQuery
  4. # shared methods for queries
  5. 1 module QueryHelper
  6. 1 def direct_subqueries
  7. 8392 subqueries_with_fasten :direct
  8. end
  9. 1 def subqueries_with_fasten fasten
  10. 8592 list = []
  11. 8592 subqueries.each do |s|
  12. 4206 next unless Array.wrap(fasten).include? s.fasten
  13. 200 list << s
  14. 200 list += s.subqueries_with_fasten s.fasten
  15. end
  16. 8592 list
  17. end
  18. 1 def table_alias
  19. 45917 @table_alias ||= begin
  20. 8602 if fasten == :direct
  21. 203 @superquery.table_alias
  22. else
  23. 8399 "#{table_prefix}#{next_table_suffix}"
  24. end
  25. end
  26. end
  27. 1 def next_table_suffix
  28. 12407 return root.next_table_suffix unless root?
  29. 8399 @table_suffix = (@table_suffix || -1) + 1
  30. end
  31. 1 def fld field_name
  32. 5294 "#{table_alias}.#{field_name}"
  33. end
  34. 1 def add_condition *args
  35. 10378 @conditions <<
  36. 10378 if args.size > 1
  37. 5192 [args.shift, Query::Value.new(args.shift, self)]
  38. else
  39. 5186 args[0]
  40. end
  41. end
  42. 1 def current_conjunction
  43. 2939 "AND"
  44. end
  45. end
  46. end
  47. end
  48. end

card/lib/card/query/abstract_query/tie.rb

100.0% lines covered

52 relevant lines. 52 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. 1 class AbstractQuery
  4. # The "Tie" methods support tying two queries (CardQuery, ReferenceQuery, etc)
  5. # together. The "fasten" variable determines which tying strategy is used.
  6. #
  7. # We currently support three values for "fasten": :join, :exist, and :in
  8. #
  9. # In concept, here's how the different strategies would tie table A to table B
  10. # in SQL assuming A.id = B.a_id
  11. #
  12. # - :join ... FROM A JOIN B ON A.id = B.a_id
  13. # - :exist ... FROM A WHERE EXISTS (SELECT * FROM B WHERE A.id = B.a_id ...)
  14. # - :in ... FROM A WHERE A.id IN (SELECT B.a_id FROM B WHERE ...)
  15. #
  16. # The different strategies will return the same values but the relative speed is
  17. # context dependent.
  18. 1 module Tie
  19. 1 def tie subquery_type, val, fields={}, subquery_args={}
  20. 4005 subquery = tie_subquery subquery_type, subquery_args
  21. 4005 subquery.interpret val
  22. 4005 fields = { from: :id, to: :id }.merge fields
  23. 4005 fasten_tie subquery, fields
  24. end
  25. 1 def tie_subquery subquery_type, subquery_args
  26. 4005 subquery_args[:class] = Query.class_for subquery_type
  27. 4005 subquery(subquery_args)
  28. end
  29. 1 def fasten_tie subquery, fields={}
  30. 4005 method = "tie_with_#{subquery.fasten}"
  31. 4005 send method, subquery, fields
  32. 4005 subquery
  33. end
  34. 1 def tie_with_join subquery, fields={}
  35. 3877 join = Join.new tie_with_join_args(subquery, fields)
  36. 3877 negate_join(subquery, join, fields) if subquery.negate
  37. 3877 joins << join
  38. end
  39. 1 def tie_with_in subquery, fields
  40. 64 subquery.mods[:return] = fields[:to]
  41. 64 subquery.mods[:in_field] = fld(fields[:from])
  42. end
  43. 1 def tie_with_exist subquery, fields
  44. 64 subquery.super_conditions fields if fields.present?
  45. end
  46. 1 def fasten
  47. 25341 @fasten ||= root? ? :join : inherit_fasten
  48. end
  49. 1 def tie_with_join_args subquery, fields
  50. 3877 args = { from: self, from_field: fields[:from],
  51. to: subquery, to_field: fields[:to] }
  52. 3877 args[:side] = :left if left_join? subquery
  53. 3877 args
  54. end
  55. 1 def left_join? subquery
  56. 3877 current_conjunction == "or" || subquery.negate
  57. # reverse conjunction if negated?
  58. end
  59. 1 def negate_join subquery, join, fields
  60. 88 subquery.conditions_on_join = join
  61. 88 add_condition "#{subquery.fld fields[:to]} is null"
  62. end
  63. 1 def inherit_fasten
  64. 4067 superfasten = superquery.fasten
  65. 4067 superfasten == :direct ? superquery.inherit_fasten : superfasten
  66. end
  67. 1 def super_conditions fields
  68. 64 superfield fields[:to], fields[:from]
  69. end
  70. 1 def superfield myfield, superfield
  71. 64 add_condition "#{fld myfield} = #{superquery.fld superfield}"
  72. end
  73. 1 def restrict id_field, val
  74. 1979 if (id = id_from_val(val))
  75. 1571 interpret id_field => id
  76. else
  77. 408 tie :card, val, from: id_field
  78. end
  79. end
  80. 1 def id_from_val val
  81. 4482 case val
  82. 839 when Integer then val
  83. 3222 when String then Card.fetch_id(val) || -999
  84. 3 when Symbol then Card::Codename.id(val) || -999
  85. end
  86. end
  87. end
  88. end
  89. end
  90. end

card/lib/card/query/act_query.rb

100.0% lines covered

13 relevant lines. 13 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. # support CQL queries that require the card_acts table
  4. 1 class ActQuery < AbstractQuery
  5. 1 def table
  6. 416 "card_acts"
  7. end
  8. 1 def table_prefix
  9. 219 "cx"
  10. end
  11. 1 def action_on card
  12. 189 tie :action, { action_on: card }, to: :card_act_id
  13. end
  14. 1 def update_action_on card
  15. 12 tie :action, { update_action_on: card }, to: :card_act_id
  16. end
  17. 1 def act_by card
  18. 18 tie :card, card, from: :actor_id
  19. end
  20. end
  21. end
  22. end

card/lib/card/query/action_query.rb

100.0% lines covered

19 relevant lines. 19 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. # support CQL queries that require the card_acts table
  4. 1 class ActionQuery < AbstractQuery
  5. 1 def table
  6. 416 "card_actions"
  7. end
  8. 1 def table_prefix
  9. 219 "cn"
  10. end
  11. 1 def action_by card
  12. 18 tie :act, { act_by: card }, from: :card_act_id
  13. end
  14. 1 def update_action_by card
  15. 6 add_update_condition
  16. 6 action_by card
  17. end
  18. 1 def action_on card
  19. 201 tie :card, card, from: :card_id
  20. end
  21. 1 def update_action_on card
  22. 12 add_update_condition
  23. 12 action_on card
  24. end
  25. 1 def add_update_condition
  26. 18 add_condition "#{fld :action_type} = 1"
  27. end
  28. end
  29. end
  30. end

card/lib/card/query/card_query.rb

100.0% lines covered

30 relevant lines. 30 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. # interpret CQL queries, transform them into SQL, and run them.
  4. 1 class CardQuery < AbstractQuery
  5. 1 include Clause
  6. 1 include Run
  7. 1 include MatchAttributes
  8. 1 include RelationalAttributes
  9. 1 include ReferenceAttributes
  10. 1 include FoundBy
  11. 1 include Interpretation
  12. 1 include Normalization
  13. 1 include Sorting
  14. 1 include Conjunctions
  15. # Query Execution
  16. # By default a query returns card objects. This is accomplished by returning
  17. # a card identifier from SQL and then hooking into our caching system (see
  18. # Card::Fetch)
  19. 1 def self.viewable_sql
  20. 3 Card::Query::SqlStatement.new.permission_conditions("cards")
  21. end
  22. 1 def table
  23. 8929 "cards"
  24. end
  25. 1 def table_prefix
  26. 5458 "c"
  27. end
  28. 1 def initialize statement, comment=nil
  29. 5661 super statement
  30. 5661 @comment = comment || default_comment
  31. 5661 interpret @statement
  32. end
  33. 1 def default_comment
  34. 1965 return if @superquery || !Card.config.sql_comments
  35. 695 statement.to_s
  36. end
  37. # Query Hierarchy
  38. # @root, @subqueries, and @superquery are used to track a hierarchy of
  39. # query objects. This nesting allows to find, for example, cards that
  40. # link to cards that link to cards....
  41. 1 def limit
  42. 38 mods[:limit].to_i
  43. end
  44. 1 def full?
  45. 8890 !superquery && mods[:return] != "count"
  46. end
  47. end
  48. end
  49. end

card/lib/card/query/card_query/conjunctions.rb

100.0% lines covered

26 relevant lines. 26 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. 1 class CardQuery
  4. # conjoining conditions
  5. 1 module Conjunctions
  6. 1 def all val
  7. 4 conjoin val, :and
  8. end
  9. 1 alias_method :and, :all
  10. 1 def any val
  11. 173 conjoin val, :or
  12. end
  13. 1 alias_method :or, :any
  14. 1 alias_method :in, :any
  15. 1 def not val
  16. 88 tie :card, val, { id: :id }, negate: true
  17. end
  18. 1 def current_conjunction
  19. 6535 @mods[:conj].blank? ? :and : @mods[:conj]
  20. end
  21. 1 private
  22. 1 def conjunction val
  23. 305 return unless [String, Symbol].member? val.class
  24. 28 CONJUNCTIONS[val.to_sym]
  25. end
  26. 1 def conjoin val, conj
  27. 177 subquery = subquery fasten: :direct, conj: conj
  28. 177 conjoinable_val(val).each do |val_item|
  29. 344 subquery.interpret val_item
  30. end
  31. end
  32. 1 def conjoinable_val val
  33. 177 return val if val.is_a? Array
  34. 509 clause_to_hash(val).map { |key, value| { key => value } }
  35. end
  36. end
  37. end
  38. end
  39. end

card/lib/card/query/card_query/found_by.rb

95.24% lines covered

21 relevant lines. 20 lines covered and 1 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. 1 class CardQuery
  4. # nest independent query
  5. 1 module FoundBy
  6. 1 def found_by val
  7. 29 found_by_cards(val).compact.each do |card|
  8. 29 subquery found_by_subquery(card)
  9. end
  10. end
  11. 1 private
  12. 1 def found_by_subquery card
  13. 29 found_by_statement(card).merge(fasten: :direct, context: card.name)
  14. end
  15. 1 def found_by_statement card
  16. 29 card&.try(:cql_hash) || invalid_found_by_card!(card)
  17. end
  18. 1 def invalid_found_by_card! card
  19. 3 raise Card::Error::BadQuery, '"found_by" value must be valid Search, ' \
  20. "but #{card.name} is a #{card.type_name}"
  21. end
  22. 1 def found_by_cards val
  23. 29 if val.is_a? Hash
  24. Query.run val
  25. else
  26. 29 fetch_found_by_cards val
  27. end
  28. end
  29. 1 def fetch_found_by_cards val
  30. 29 Array.wrap(val).map do |v|
  31. 29 Card.fetch v.to_name.absolute(context), new: {}
  32. end
  33. end
  34. end
  35. end
  36. end
  37. end

card/lib/card/query/card_query/interpretation.rb

95.92% lines covered

49 relevant lines. 47 lines covered and 2 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. 1 class CardQuery
  4. # Interpret CQL. Once interpreted, SQL can be generated.
  5. 1 module Interpretation
  6. 1 INTERPRET_METHOD = { basic: :add_condition,
  7. relational: :relate,
  8. plus_relational: :relate_compound,
  9. conjunction: :send }.freeze
  10. # normalize and extract meaning from a clause
  11. # @param clause [Hash, String, Integer] statement or chunk thereof
  12. 1 def interpret clause
  13. 8688 normalize_clause(clause).each do |key, val|
  14. 13961 interpret_item key, val
  15. end
  16. end
  17. 1 def interpret_item key, val
  18. 13961 if interpret_as_content? key
  19. 32 interpret content: [key, val]
  20. 13929 elsif interpret_as_modifier? key, val
  21. 3366 interpret_modifier key, val
  22. else
  23. 10563 interpret_attributes key, val
  24. end
  25. end
  26. 1 def interpret_as_content? key
  27. # eg "match" is both operator and attribute;
  28. # interpret as attribute when "match" is key
  29. 13961 OPERATORS.key?(key.to_s) && !ATTRIBUTES[key]
  30. end
  31. 1 def interpret_as_modifier? key, val
  32. # eg when "sort" is hash, it can have subqueries
  33. # and must be interpreted like an attribute
  34. 13929 MODIFIERS.key?(key) && !val.is_a?(Hash)
  35. end
  36. 1 def interpret_modifier key, val
  37. 3366 @mods[key] = val.is_a?(Array) ? val : val.to_s
  38. end
  39. 1 def interpret_attributes attribute, val
  40. 10563 attribute_type = ATTRIBUTES[attribute]
  41. 10563 if (method = INTERPRET_METHOD[attribute_type])
  42. 10556 send method, attribute, val
  43. else
  44. 7 no_method_for_attribute_type attribute, attribute_type
  45. end
  46. end
  47. 1 def no_method_for_attribute_type attribute, type
  48. 7 return if type == :ignore
  49. 1 if type == :deprecated
  50. 1 deprecated_attribute attribute
  51. else
  52. bad_attribute! attribute
  53. end
  54. end
  55. 1 def deprecated_attribute attribute
  56. 1 Rails.logger.info "Card queries no longer support #{attribute} attribute"
  57. end
  58. 1 def bad_attribute! attribute
  59. raise Error::BadQuery, "Invalid attribute: #{attribute}"
  60. end
  61. 1 def relate_compound key, val
  62. has_multiple_values =
  63. 354 val.is_a?(Array) &&
  64. 291 (val.first.is_a?(Array) || conjunction(val.first).present?)
  65. 354 relate key, val, multiple: has_multiple_values
  66. end
  67. 1 def relate key, val, opts={}
  68. 5350 multiple = opts[:multiple].nil? ? val.is_a?(Array) : opts[:multiple]
  69. 5350 method = opts[:method] || :send
  70. 5350 if multiple
  71. 9 relate_multi_value method, key, val
  72. else
  73. 5341 send method, key, val
  74. end
  75. end
  76. 1 def relate_multi_value method, key, val
  77. 9 conj = conjunction(val.first) ? conjunction(val.shift) : :and
  78. 9 if conj == current_conjunction
  79. # same conjunction as container, no need for subcondition
  80. 18 val.each { |v| send method, key, v }
  81. else
  82. 9 send conj, (val.map { |v| { key => v } })
  83. end
  84. end
  85. end
  86. end
  87. end
  88. end

card/lib/card/query/card_query/match_attributes.rb

100.0% lines covered

20 relevant lines. 20 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. 1 class CardQuery
  4. # Implements the match attributes that match always against content and/or name.
  5. # Currently that's different from the match operator that can be restricted to
  6. # names or content.
  7. # Example: { match: "name or content" } vs. { name: ["match", "a name"] }
  8. # TODO: unify handling for both using full text indexing
  9. 1 module MatchAttributes
  10. # match term anywhere in name or content
  11. 1 def match val
  12. 18 return unless val.present?
  13. 18 subconds = %i[name content].map do |field|
  14. 36 Value.new([:match, val], self).to_sql field
  15. end
  16. 18 add_condition or_join(subconds)
  17. end
  18. # match names beginning with term
  19. 1 def complete val
  20. 2 val = val.to_name
  21. 2 if val.junction?
  22. 1 interpret left: val.left
  23. 1 interpret right: { complete: val.right } if val.right.present?
  24. else
  25. 1 add_condition "#{table_alias}.key LIKE '#{val.to_name.key}%'"
  26. end
  27. end
  28. # match term anywhere in name
  29. # DEPRECATE - move handling to name: ["match", val]
  30. 1 def name_match val
  31. 1 interpret name: [:match, val]
  32. end
  33. 1 private
  34. 1 def or_join conditions
  35. 18 "(#{Array(conditions).join ' OR '})"
  36. end
  37. end
  38. end
  39. end
  40. end

card/lib/card/query/card_query/normalization.rb

90.91% lines covered

33 relevant lines. 30 lines covered and 3 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. 1 class CardQuery
  4. # normalize clause's keys and values.
  5. 1 module Normalization
  6. 1 def normalize_clause clause
  7. 8688 clause = clause_to_hash clause
  8. 8688 clause.symbolize_keys!
  9. 8688 clause.each do |key, val|
  10. 13967 next if key.to_sym == :return
  11. # when return values are relative, they are relative to the name of the
  12. # card returned, not the context card
  13. 12079 clause[key] = normalize_value val
  14. end
  15. 8688 clause
  16. end
  17. 1 def clause_to_hash clause
  18. 9194 case clause
  19. 8971 when Hash then clause
  20. 186 when Integer then { id: clause }
  21. 37 when String then { id: (Card::Lexicon.id(clause) || -2) }
  22. when Symbol then { id: Card::Codename.id(clause) }
  23. else raise Error::BadQuery, "Invalid clause: #{clause.inspect}"
  24. end
  25. end
  26. 1 def normalize_value val
  27. 13387 case val
  28. 8481 when Integer, Float, Hash, Symbol, NilClass then val
  29. 4465 when String then normalize_string_value val
  30. 441 when Array then normalize_array_value val
  31. else raise Error::BadQuery, "Invalid value type: #{val.class} (#{val.inspect})"
  32. end
  33. end
  34. 1 def normalize_array_value val
  35. 1749 val.map { |v| normalize_value v }
  36. end
  37. 1 def normalize_string_value val
  38. 4465 case val.to_s
  39. when /^\$(\w+)$/
  40. # replace from @vars when value starts with dollar sign
  41. 2 string_value_from_var Regexp.last_match[1]
  42. when /\b_/
  43. # absolutize based on @context when there are words beginning with "_"
  44. 208 val.to_name.absolute(context)
  45. else
  46. 4255 val
  47. end
  48. end
  49. 1 def string_value_from_var varname
  50. 2 @vars[varname.to_sym].to_s.strip
  51. end
  52. end
  53. end
  54. end
  55. end

card/lib/card/query/card_query/reference_attributes.rb

100.0% lines covered

15 relevant lines. 15 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. 1 class CardQuery
  4. # interpret CQL attributes that involve references from one card to another
  5. 1 module ReferenceAttributes
  6. 1 def self.define_reference_method methodname, reftype, ref_method, ref_field
  7. 8 define_method methodname do |val|
  8. 2503 tie :reference,
  9. { ref_method => { reftype: reftype, card: val } },
  10. to: ref_field
  11. end
  12. end
  13. {
  14. 1 refer_to: %w[L I],
  15. link_to: "L",
  16. include: "I",
  17. nest: "I"
  18. }.each do |methodname, reftype|
  19. 4 define_reference_method methodname, reftype, :referee, :referer_id
  20. end
  21. {
  22. 1 referred_to_by: %w[L I],
  23. linked_to_by: "L",
  24. included_by: "I",
  25. nested_by: "I"
  26. }.each do |methodname, reftype|
  27. 4 define_reference_method methodname, reftype, :referer, :referee_id
  28. end
  29. # shortcut methods for role references
  30. # DEPRECATE?
  31. 1 def member_of val
  32. 10 interpret right_plus: [Card::RolesID, refer_to: val]
  33. end
  34. 1 def member val
  35. 3 interpret referred_to_by: { left: val, right: Card::RolesID }
  36. end
  37. end
  38. end
  39. end
  40. end

card/lib/card/query/card_query/relational_attributes.rb

100.0% lines covered

45 relevant lines. 45 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. 1 class CardQuery
  4. # interpret CQL attributes that relate multiple cards
  5. # each method below corresponds to a relational CQL term
  6. #
  7. # NOTE: methods using "restrict" can be executed without
  8. # tying in an additional query if the val in question can be
  9. # reduced to an id.
  10. 1 module RelationalAttributes
  11. 1 def type val
  12. 312 restrict :type_id, val
  13. end
  14. 1 def part val
  15. 137 right_val = val.is_a?(Integer) ? val : val.clone
  16. 137 any(left: val, right: right_val)
  17. end
  18. 1 def left val
  19. 968 restrict :left_id, val
  20. end
  21. 1 def right val
  22. 693 restrict :right_id, val
  23. end
  24. 1 def editor_of val
  25. 189 tie_act :action_on, val
  26. end
  27. 1 def updater_of val
  28. 12 tie_act :update_action_on, val
  29. end
  30. 1 def edited_by val
  31. 12 tie_action :action_by, val
  32. end
  33. 1 def updated_by val
  34. 6 tie_action :update_action_by, val
  35. end
  36. 1 def last_editor_of val
  37. 3 tie :card, val, to: :updater_id
  38. end
  39. 1 def last_edited_by val
  40. 3 restrict :updater_id, val
  41. end
  42. 1 def creator_of val
  43. 3 tie :card, val, to: :creator_id
  44. end
  45. 1 def created_by val
  46. 3 restrict :creator_id, val
  47. end
  48. # ~~~~~~ PLUS RELATIONAL
  49. 1 def left_plus val
  50. 23 junction val, :left, :right_id
  51. end
  52. 1 def right_plus val
  53. 310 junction val, :right, :left_id
  54. end
  55. 1 def plus val
  56. 23 any(left_plus: val, right_plus: val.deep_clone)
  57. end
  58. 1 private
  59. 1 def tie_action action, val
  60. 18 tie :action, { action => val }, to: :card_id
  61. end
  62. 1 def tie_act action, val
  63. 201 tie :act, { action => val }, to: :actor_id
  64. end
  65. 1 def junction val, side, field
  66. 333 tie :card, junction_val(val, side), to: field
  67. end
  68. 1 def junction_val val, side
  69. 333 part_clause, junction_clause = val.is_a?(Array) ? val : [val, {}]
  70. 333 clause_to_hash(junction_clause).merge side => part_clause
  71. end
  72. end
  73. end
  74. end
  75. end

card/lib/card/query/card_query/run.rb

90.0% lines covered

60 relevant lines. 54 lines covered and 6 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. 1 class CardQuery
  4. # run CQL queries
  5. 1 module Run
  6. # run the current query
  7. # @return [Array] of card objects by default
  8. 1 def run
  9. 4380 retrn = statement[:return].present? ? statement[:return].to_s : "card"
  10. 4380 return_method = :"return_#{simple_result?(retrn) ? :simple : :list}"
  11. 4380 send return_method, run_sql, retrn
  12. end
  13. # @return [(not an Array)]
  14. 1 def return_simple sql_result, retrn
  15. 16773 send result_method(retrn), sql_result, retrn
  16. end
  17. # @return [Array]
  18. 1 def return_list sql_results, retrn
  19. 4355 large_list sql_results.length if sql_results.length > 1000
  20. 4355 sql_results.map do |record|
  21. 16748 return_simple record, retrn
  22. end
  23. end
  24. 1 def large_list length
  25. Rails.logger.info "#{length} records returned by #{@statement}"
  26. end
  27. 1 def result_method retrn
  28. case
  29. 33540 when respond_to?(:"#{retrn}_result") then :"#{retrn}_result"
  30. when (retrn =~ /id$/) then :id_result
  31. 6 when (retrn =~ /_\w+/) then :name_result
  32. when (retrn == "key") then :key_result
  33. else :default_result
  34. end
  35. end
  36. 1 def count_result results, _field
  37. 25 results.first["count"].to_i
  38. end
  39. 1 def default_result record, field
  40. record[field]
  41. end
  42. 1 def id_result record, field
  43. 799 record[field].to_i
  44. end
  45. 1 def raw_result record, _field
  46. record
  47. end
  48. 1 def key_result record, pattern=""
  49. 10 name_result(record, pattern).to_name.key
  50. end
  51. 1 def name_result record, pattern=""
  52. 15366 name = record["name"]&.to_name
  53. 15366 name ||= Card::Lexicon.lex_to_name [record["left_id"], record["right_id"]]
  54. 15366 process_name name, pattern
  55. end
  56. 1 def card_result record, _field
  57. 587 if alter_results?
  58. 4 Card.fetch name_result(record), new: {}
  59. else
  60. 583 fetch_or_instantiate record
  61. end
  62. end
  63. 1 def fetch_or_instantiate record
  64. 583 card = Card.retrieve_from_cache_by_id record["id"]
  65. 583 unless card
  66. 239 card = Card.instantiate record
  67. 239 Card.write_to_cache card
  68. end
  69. 583 card.include_set_modules
  70. 583 card
  71. end
  72. 1 def run_sql
  73. # puts "\nSQL = #{sql}"
  74. 4380 ActiveRecord::Base.connection.select_all sql
  75. end
  76. 1 def process_name name, pattern=""
  77. 15366 name = pattern.to_name.absolute(name) if pattern =~ /_\w+/
  78. 15366 return name unless alter_results?
  79. 13 alter_result name
  80. end
  81. 1 def alter_result name
  82. 13 name_parts = [statement[:prepend], name, statement[:append]].compact
  83. 13 Card::Name[name_parts]
  84. end
  85. 1 def simple_result? retrn
  86. 4380 retrn == "count"
  87. end
  88. 1 def alter_results?
  89. 15953 statement[:prepend] || statement[:append]
  90. end
  91. end
  92. end
  93. end
  94. end

card/lib/card/query/card_query/sorting.rb

97.96% lines covered

49 relevant lines. 48 lines covered and 1 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. 1 class CardQuery
  4. # handle relational (not simple) CQL sort values
  5. #
  6. # sorting with subqueries is not fully supported; only a few experimental
  7. # examples have been attempted, and even for those the syntax is likely
  8. # to change.
  9. #
  10. # Generally speaking, sorting subqueries will require a JOIN strategy (as
  11. # opposed to the "WHERE EXISTS" strategy that is central to queries' main
  12. # conditions.)
  13. 1 module Sorting
  14. 1 SORT_BY_ITEM_JOIN_MAP = { left: "left_id", right: "right_id" }.freeze
  15. 1 def sort val
  16. 2 return nil unless full?
  17. 2 sort_field = val[:return] || "db_content"
  18. 2 val = val.clone
  19. 2 item = val.delete(:item) || "left"
  20. 2 sort_by val, item, sort_field
  21. end
  22. 1 def sort_by val, item, sort_field
  23. 2 if sort_field == "count"
  24. 1 sort_by_count val, item
  25. else
  26. 1 sort_by_item_join val, item, sort_field
  27. end
  28. end
  29. 1 def sort_by_item_join val, item, sort_field
  30. 1 join_field = sort_by_item_join_field item
  31. 1 join = join_cards val, to_field: join_field,
  32. side: "LEFT",
  33. conditions_on_join: true
  34. 1 @mods[:sort] ||= "#{join.table_alias}.#{sort_field}"
  35. end
  36. 1 def sort_by_item_join_field item
  37. 1 SORT_BY_ITEM_JOIN_MAP[item.to_sym] || sort_method_not_implemented(:join, item)
  38. end
  39. # EXPERIMENTAL!
  40. # sort: { referred_to_by { right: "*follow" }, return count }
  41. 1 def sort_by_count val, item
  42. 1 method_name = "sort_by_count_#{item}"
  43. 1 sort_method_not_implemented :count, item unless respond_to? method_name
  44. 1 send method_name, val
  45. end
  46. 1 def sort_method_not_implemented method, item
  47. raise Card::Error::BadQuery, "sorting by ##{method}/#{item} not yet implemented"
  48. end
  49. 1 def sort_by_count_referred_to val
  50. 1 @mods[:sort] = "coalesce(count,0)" # needed for postgres
  51. 1 sort_query = count_sort_query
  52. 1 sort_query.add_condition "referer_id in (#{count_subselect(val).sql})"
  53. # FIXME: - SQL generated before SQL phase
  54. 1 sort_query.joins << Join.new(from: sort_query, side: "LEFT",
  55. to: %w[card_references wr referee_id])
  56. 1 join_count_sort_query sort_query
  57. end
  58. 1 def join_count_sort_query sort_query
  59. 1 sort_query.mods[:sort_join_field] =
  60. "#{sort_query.table_alias}.id as sort_join_field"
  61. # FIXME: HACK!
  62. 1 joins << Join.new(from: self, side: "LEFT",
  63. to: [sort_query, "srtbl", "sort_join_field"])
  64. end
  65. 1 def count_subselect val
  66. 1 Query.new val.merge(return: "id", superquery: self)
  67. end
  68. 1 def count_sort_query
  69. 1 Query.new return: "coalesce(count(*), 0) as count",
  70. group: "sort_join_field",
  71. superquery: self
  72. end
  73. 1 def join_cards val, opts={}
  74. 1 conditions_on_join = opts.delete :conditions_on_join
  75. 1 s = subquery
  76. 1 join_opts = { from: self, to: s }.merge opts
  77. 1 card_join = Join.new join_opts
  78. 1 joins << card_join unless opts[:from].is_a? Join
  79. 1 s.conditions_on_join = card_join if conditions_on_join
  80. 1 s.interpret val
  81. 1 s
  82. end
  83. end
  84. end
  85. end
  86. end

card/lib/card/query/clause.rb

100.0% lines covered

9 relevant lines. 9 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. 1 module Clause
  4. # attr_accessor :clause
  5. 1 def safe_sql text
  6. 5027 Query.safe_sql text
  7. end
  8. 1 def quote v
  9. 5639 connection.quote(v)
  10. end
  11. 1 def connection
  12. 5679 @connection ||= ActiveRecord::Base.connection
  13. end
  14. end
  15. end
  16. end

card/lib/card/query/join.rb

84.0% lines covered

50 relevant lines. 42 lines covered and 8 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. # object representation of Card::Query joins
  4. 1 class Join
  5. 1 JOIN_OPT_KEYS = %i[side conditions
  6. from from_table from_alias from_field
  7. to to_table to_alias to_field].freeze
  8. 1 attr_accessor(*JOIN_OPT_KEYS)
  9. # These two manage hierarchy of nested joins
  10. 1 attr_accessor :superjoin, :subjoins
  11. # This example join clause:
  12. #
  13. # cards c LEFT JOIN card_actions ca on c.id = ca.card_id and ca.draft is null
  14. #
  15. # ...would translate into the following instance variables on the Join object:
  16. #
  17. # @side = "left"
  18. # @from_table = "cards"
  19. # @from_alias = "c"
  20. # @from_field = "id"
  21. # @to_table = "card_actions"
  22. # @to_alias = "ca"
  23. # @to_field = "card_id"
  24. # @conditions = "ca.draft is null"
  25. #
  26. # all of the above can be set directly via opts using the keys with the same name.
  27. #
  28. # Join.new side: "left", from_table: "cards"...
  29. #
  30. # The from and to fields can also be set via :from and :to keys.
  31. # (see #interpret_from_and_to)
  32. #
  33. # You can generally use Symbols in place of Strings where applicable.
  34. #
  35. 1 def initialize opts={}
  36. 3880 interpret_from_and_to opts
  37. 3880 convert_opts_to_instance_variables opts
  38. 3880 @conditions = Array(@conditions).compact
  39. 3880 @subjoins = []
  40. 3880 register_superjoin
  41. end
  42. 1 def side
  43. 7760 if !@side.nil?
  44. 248 @side.to_s.upcase
  45. else
  46. 7512 @side = inside_or? ? "LEFT" : nil
  47. end
  48. end
  49. 1 def left?
  50. 3880 side == "LEFT"
  51. end
  52. 1 private
  53. 1 def inside_or?
  54. 7512 from&.is_a?(Card::Query) && from.mods[:conj] == "or"
  55. end
  56. # the options :to and :from can be translated into the full table/alias/field trio.
  57. #
  58. # - An Array is interpreted in that order (table, alias, field)
  59. # - A Hash expects the keys :table, :alias, and (optionally) :field
  60. # - A table and alias can be inferred from Card::Query or Card::Query::Reference
  61. # objects.
  62. # - They can also be inferred from a Join object, but only as a :from value
  63. #
  64. # In all cases, if the field is not specified, it is assumed to be :id
  65. 1 def interpret_from_and_to opts
  66. 3880 %i[from to].each do |side|
  67. 7760 directional_hash_for_object(side, opts[side]).map do |key, value|
  68. 23280 opts[:"#{side}_#{key}"] ||= value
  69. end
  70. end
  71. end
  72. 1 def directional_hash_for_object side, object
  73. 7760 case object
  74. when nil then nil
  75. when Hash then object
  76. 2 when Array then dir_hash(*object)
  77. 7758 when AbstractQuery then dir_hash_for_query object
  78. when Join then dir_hash_for_join side, object
  79. else dir_error(side, object)
  80. end
  81. end
  82. 1 def dir_hash table, table_alias, field=nil
  83. 7760 hash = { table: table, alias: table_alias }
  84. 7760 hash[:field] = field || :id
  85. 7760 hash
  86. end
  87. 1 def dir_hash_for_query query
  88. 7758 dir_hash query.table, query.table_alias
  89. end
  90. 1 def dir_hash_for_join side, object
  91. raise "to: cannot be Join" if side == :to
  92. dir_hash object.to_table, object.to_alias
  93. end
  94. 1 def dir_error side, object
  95. raise Card::Error::BadQuery, "invalid #{side} option: #{object}"
  96. end
  97. 1 def convert_opts_to_instance_variables opts
  98. 3880 opts.each do |key, value|
  99. 31164 send "#{key}=", value if value.present? && JOIN_OPT_KEYS.member?(key)
  100. end
  101. end
  102. 1 def register_superjoin
  103. 3880 return unless @from.is_a? Join
  104. @superjoin = @from
  105. @superjoin.subjoins << self
  106. end
  107. end
  108. end
  109. end

card/lib/card/query/reference_query.rb

93.33% lines covered

30 relevant lines. 28 lines covered and 2 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. # support the use of the card_references table in CQL
  4. 1 class ReferenceQuery < AbstractQuery
  5. 1 def table
  6. 2511 "card_references"
  7. end
  8. 1 def table_prefix
  9. 2503 "cr"
  10. end
  11. 1 def referer hash
  12. 44 add_conditions :referer_id, hash
  13. end
  14. 1 def referee hash
  15. 2459 add_conditions :referee_id, hash
  16. end
  17. 1 def add_conditions outfield, hash
  18. 2503 add_reftype_condition hash[:reftype]
  19. 2503 add_outfield_condition outfield, hash[:card]
  20. end
  21. 1 def add_outfield_condition outfield, outcard
  22. 2503 if outcard == "_none"
  23. non_outfield
  24. 2503 elsif (id = id_from_val(outcard))
  25. 2493 outfield_id outfield, id
  26. else
  27. 10 tie :card, outcard, from: outfield
  28. end
  29. end
  30. 1 def non_outfield
  31. add_condition "#{fld :is_present} = 0"
  32. end
  33. 1 def outfield_id outfield, id
  34. 2493 add_condition "#{fld(outfield)} = #{id}"
  35. end
  36. 1 def add_reftype_condition reftype
  37. 2503 return unless reftype.present?
  38. 2503 reftype = Array.wrap reftype
  39. 2503 operator = (reftype.size == 1 ? "=" : "IN")
  40. 5190 quoted_letters = reftype.map { |letter| "'#{letter}'" } * ", "
  41. 2503 add_condition "#{fld(:ref_type)} #{operator} (#{quoted_letters})"
  42. end
  43. end
  44. end
  45. end

card/lib/card/query/sql_statement.rb

98.48% lines covered

66 relevant lines. 65 lines covered and 1 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. # The SqlStatement class generates sql from the Query classes. However, the logic
  4. # is not yet as cleanly separated as it should be.
  5. # At present, SqlStatement contains (imho) too much knowledge about card constructs.
  6. # For example, all the permission and trash handling is here.
  7. #
  8. # In principle, the Query class should "interpret" statements into a few objects and
  9. # a clean Query hierarchy. The SqlStatement class should be able to traverse that
  10. # hierarchy and do little more than run "to_sql" on its parts, and in so doing
  11. # construct a valid SQL statement.
  12. 1 class SqlStatement
  13. 1 include Joins
  14. 1 include Where
  15. 1 include Order
  16. 1 def initialize query=nil
  17. 4517 @query = query
  18. 4517 @mods = query&.mods
  19. end
  20. 1 def build
  21. 4514 @fields = fields
  22. 4514 @tables = tables
  23. 4514 @joins = joins
  24. 4514 @where = where
  25. 4514 @group = group
  26. 4514 @order = order
  27. 4514 @limit_and_offset = limit_and_offset
  28. 4514 self
  29. end
  30. 1 def to_s
  31. [
  32. 4514 comment, select, from, @joins, @where, @group, @order, @limit_and_offset
  33. ].compact.join " "
  34. end
  35. 1 def select
  36. 4514 "#{leading_space}SELECT DISTINCT #{@fields}"
  37. end
  38. 1 def from
  39. 4514 "FROM #{@tables}"
  40. end
  41. 1 def leading_space
  42. 8522 " " * (@query.depth * 2)
  43. end
  44. 1 def comment
  45. 4514 return nil unless Card.config.sql_comments && @query.comment
  46. 4384 "/* #{@query.comment} */\n"
  47. end
  48. 1 def tables
  49. 4514 "#{@query.table} #{@query.table_alias}"
  50. end
  51. 1 def fields
  52. 4514 table = @query.table_alias
  53. 4514 field = @mods[:return] unless @mods[:return] =~ /^_\w+/
  54. 4514 field = field.blank? ? :card : field.to_sym
  55. 4514 field = full_field(table, field)
  56. 4514 [field, @mods[:sort_join_field]].compact * ", "
  57. end
  58. 1 def full_field table, field
  59. 4514 case field
  60. 2606 when :card, :raw then "#{table}.*"
  61. when :content then "#{table}.db_content"
  62. 614 when :name, :key then "#{table}.name, #{table}.left_id, #{table}.right_id"
  63. 25 when :count then "coalesce(count( distinct #{table}.id),0) as count"
  64. else
  65. 1269 standard_full_field table, field
  66. end
  67. end
  68. 1 def standard_full_field table, field
  69. 1269 if ATTRIBUTES[field.to_sym] == :basic
  70. 1239 "#{table}.#{field}"
  71. else
  72. 30 safe_sql field
  73. end
  74. end
  75. 1 def group
  76. 4514 group = @mods[:group]
  77. 4514 "GROUP BY #{safe_sql group}" if group.present?
  78. end
  79. 1 def limit_and_offset
  80. 4514 full_syntax do
  81. 4359 limit = @mods[:limit]
  82. 4359 offset = @mods[:offset]
  83. 4359 if limit.to_i.positive?
  84. 22 string = "LIMIT #{limit.to_i} "
  85. 22 string += "OFFSET #{offset.to_i} " if offset.present?
  86. 22 string
  87. end
  88. end
  89. end
  90. 1 def full_syntax
  91. 9028 @query.full? ? yield : return
  92. end
  93. 1 def safe_sql txt
  94. 36 Query.safe_sql txt
  95. end
  96. 1 def cast_type type
  97. 1 cxn ||= ActiveRecord::Base.connection
  98. 1 (val = cxn.cast_types[type.to_sym]) ? val[:name] : safe_sql(type)
  99. end
  100. end
  101. end
  102. end

card/lib/card/query/sql_statement/joins.rb

100.0% lines covered

37 relevant lines. 37 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. 1 class SqlStatement
  4. # transform joins from Card::Query::Join objects to SQL string clause
  5. 1 module Joins
  6. 1 def joins query=nil
  7. 8392 query ||= @query
  8. 8392 joins_on_query(query).map do |join|
  9. 3880 join_clause join
  10. end.flatten.join " "
  11. end
  12. 1 def joins_on_query query
  13. 8392 query.direct_subqueries.unshift(query).map(&:joins).flatten
  14. end
  15. 1 def join_clause join
  16. 3880 subclause = subjoins join
  17. 3880 table = join_table join
  18. 3880 on = on_clause join
  19. 3880 join_clause_parts(join, table, subclause, on).compact.join " "
  20. end
  21. 1 def join_clause_parts join, table, subclause, on
  22. 3880 parts = ["\n#{leading_space}", join.side, "JOIN"]
  23. 3880 if join.left? && subclause.present?
  24. 11 parts + ["(#{table} #{subclause})", on]
  25. else
  26. 3869 parts + [table, on, subclause]
  27. end
  28. end
  29. 1 def subjoins join
  30. 3880 return unless join.to.is_a? AbstractQuery
  31. 3878 joins join.to
  32. end
  33. 1 def join_table join
  34. 3880 to_table = join.to_table
  35. 3880 to_table = "(#{to_table.sql})" if to_table.is_a? CardQuery
  36. 3880 [to_table, join.to_alias].join " "
  37. end
  38. 1 def on_clause join
  39. 3880 on_conditions = join.conditions
  40. 3880 on_conditions.unshift ["#{join.from_alias}.#{join.from_field}",
  41. "#{join.to_alias}.#{join.to_field}"].join(" = ")
  42. 3880 on_conditions += on_card_conditions(join) if join.to.is_a? CardQuery
  43. 3880 on_conditions.reject!(&:blank?)
  44. 3880 "ON #{basic_conditions(on_conditions) * ' AND '}"
  45. end
  46. 1 def on_card_conditions join
  47. 1007 to = join.to
  48. 1007 explicit = to.conditions_on_join == join ? explicit_conditions(to) : nil
  49. 1007 [explicit, implicit_conditions(to)].compact
  50. end
  51. end
  52. end
  53. end
  54. end

card/lib/card/query/sql_statement/order.rb

100.0% lines covered

30 relevant lines. 30 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. # convert @query sort rep into order by statement
  4. # order information is stored in @mods[:sort], @mods[:sort_as], and
  5. # @mods[:dir]
  6. 1 class SqlStatement
  7. ORDER_MAP = {
  8. 1 "id" => "id",
  9. "update" => "updated_at",
  10. "create" => "created_at",
  11. "name" => "key",
  12. "content" => "db_content",
  13. "alpha" => "key", # DEPRECATED
  14. "relevance" => "updated_at" # DEPRECATED
  15. }.freeze
  16. # build ORDER BY clause
  17. 1 module Order
  18. 1 def order
  19. 4514 full_syntax do
  20. 4359 "ORDER BY #{order_directives.join ', '}"
  21. end
  22. end
  23. 1 def order_directives
  24. 4359 Array.wrap(order_config).map do |order_key|
  25. 4359 order_directive order_key
  26. end
  27. end
  28. 1 def order_directive order_key
  29. 4359 field = order_field order_key
  30. 4359 @fields += ", #{field}"
  31. 4359 "#{field} #{order_dir order_key}"
  32. end
  33. 1 def order_field order_key
  34. 4359 order_as do
  35. 4359 if (field = ORDER_MAP[order_key])
  36. 4357 "#{@query.table_alias}.#{field}"
  37. else
  38. 2 safe_sql order_key
  39. end
  40. end
  41. end
  42. 1 def order_as
  43. 4359 field = yield
  44. 4359 return field unless (as = @mods[:sort_as])
  45. 1 "CAST(#{field} AS #{cast_type(safe_sql(as))})"
  46. end
  47. 1 def order_dir order_key
  48. 4359 if @mods[:dir].blank?
  49. 4357 DEFAULT_ORDER_DIRS[order_key.to_sym] || "asc"
  50. else
  51. 2 safe_sql @mods[:dir]
  52. end
  53. end
  54. 1 def order_config
  55. 4359 @mods[:sort].blank? ? "update" : @mods[:sort]
  56. end
  57. end
  58. end
  59. end
  60. end

card/lib/card/query/sql_statement/where.rb

100.0% lines covered

54 relevant lines. 54 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. 1 class SqlStatement
  4. # handle where clause in SqlStatement
  5. 1 module Where
  6. 1 def where
  7. 4514 conditions = [explicit_conditions(@query), implicit_conditions(@query)]
  8. 4514 conditions = conditions.reject(&:blank?).join " AND "
  9. 4514 "WHERE #{conditions}" unless conditions.blank?
  10. end
  11. # conditions explicitly specified in the query object
  12. 1 def explicit_conditions query
  13. 8592 cond_list = basic_conditions query.conditions
  14. 8592 cond_list += conditions_from query.subqueries
  15. 8592 cond_list.reject!(&:blank?)
  16. 8592 format_conditions cond_list, query
  17. end
  18. # depending on how a query is "fastened", its conditions may be rendered
  19. # along with the superquery's
  20. 1 def conditions_from subqueries
  21. 8592 subqueries.map do |query|
  22. 4206 next if query.conditions_on_join
  23. 4117 case query.fasten
  24. 64 when :exist then exist_condition query
  25. 64 when :in then in_condition query
  26. 3989 else explicit_conditions query
  27. end
  28. end
  29. end
  30. 1 def exist_condition query
  31. 64 "#{maybe_not query}EXISTS (#{spaced_subquery_sql query})"
  32. end
  33. 1 def maybe_not query
  34. 128 query.negate ? "NOT " : ""
  35. end
  36. 1 def in_condition query
  37. 64 field = query.mods[:in_field]
  38. 64 "#{field} #{maybe_not query}IN (#{spaced_subquery_sql query})"
  39. end
  40. 1 def spaced_subquery_sql subquery
  41. 128 "\n#{subquery.sql}\n#{leading_space}"
  42. end
  43. # the conditions stored in the query's @conditions variable
  44. 1 def basic_conditions conditions
  45. 12472 conditions.map do |condition|
  46. 15347 case condition
  47. 10162 when String then condition
  48. 5185 when Array then standard_condition(condition)
  49. end
  50. end
  51. end
  52. 1 def standard_condition condition
  53. 5185 field, val = condition
  54. 5185 val.to_sql field
  55. end
  56. # handle trash and permissions
  57. # only applies to card queries
  58. 1 def implicit_conditions query
  59. 5521 return unless query.is_a?(CardQuery)
  60. 5451 table = query.table_alias
  61. 5451 [trash_condition(table), permission_conditions(table)].compact * " AND "
  62. end
  63. 1 def trash_condition table
  64. 5451 "#{table}.trash is false"
  65. end
  66. 1 def permission_conditions table
  67. 5454 return if Auth.always_ok?
  68. 948 read_rules = Auth.as_card.read_rules
  69. 948 read_rule_list = read_rules.present? ? read_rules.join(",") : 1
  70. 948 "#{table}.read_rule_id IN (#{read_rule_list})"
  71. end
  72. # convert list of conditions to string
  73. 1 def format_conditions cond_list, query
  74. 8592 if cond_list.size > 1
  75. 5588 "(#{cond_list.join condition_joint(query)})"
  76. else
  77. 3004 cond_list.join
  78. end
  79. end
  80. 1 def condition_joint query
  81. 5588 " #{query.current_conjunction.upcase} "
  82. end
  83. end
  84. end
  85. end
  86. end

card/lib/card/query/value.rb

94.34% lines covered

53 relevant lines. 50 lines covered and 3 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. # handling for CQL value clauses, eg [operator, value]
  4. 1 class Value
  5. 1 include Clause
  6. 1 include MatchValue
  7. 1 SQL_FIELD = { name: "key", content: "db_content" }.freeze
  8. 1 attr_reader :query, :operator, :value
  9. 1 def initialize rawvalue, query
  10. 5228 @query = query
  11. 5228 @operator, @value = parse_value rawvalue
  12. 5228 canonicalize_operator
  13. end
  14. 1 def to_sql field
  15. 5221 if @operator == "~"
  16. 40 match_sql field
  17. else
  18. 5181 standard_sql field
  19. end
  20. end
  21. 1 private
  22. 1 def standard_sql field
  23. 5275 @value = Array.wrap(@value).map { |v| v.to_name.key } if field.to_sym == :name
  24. 5181 "#{field_sql field} #{@operator} #{sqlize @value}"
  25. end
  26. 1 def parse_value value
  27. 5228 case value
  28. 175 when Array then parse_array_value value.clone
  29. 2 when nil then ["is", nil]
  30. 5051 else ["=", parse_simple_value(value)]
  31. end
  32. end
  33. 1 def parse_array_value array
  34. 175 operator = operator?(array.first) ? array.shift : :in
  35. 772 [operator, array.flatten.map { |i| parse_simple_value i }]
  36. end
  37. 1 def parse_simple_value value
  38. 5648 case value
  39. 5645 when String, Integer then value
  40. 1 when Symbol then value.to_s
  41. when nil then nil
  42. else raise Error::BadQuery, "Invalid property value: #{value.inspect}"
  43. end
  44. end
  45. 1 def canonicalize_operator
  46. 5228 unless (target = OPERATORS[@operator.to_s])
  47. raise Error::BadQuery, "Invalid operator: #{@operator}"
  48. end
  49. 5228 @operator = target
  50. end
  51. 1 def operator? key
  52. 175 OPERATORS.key? key.to_s
  53. end
  54. 1 def sqlize v
  55. 5804 case v
  56. when Query then v.to_sql
  57. 201 when Array then sqlize_array v
  58. 4 when nil then "NULL"
  59. 5599 else quote(v.to_s)
  60. end
  61. end
  62. 1 def sqlize_array array
  63. 201 array.flatten!
  64. 201 if array.size == 1 && !@operator.in?(["in", "not in"])
  65. 109 sqlize array.first
  66. else
  67. 606 "(#{array.map { |x| sqlize(x) }.join(',')})"
  68. end
  69. end
  70. 1 def field_sql field
  71. 5181 "#{@query.table_alias}.#{standardize_field field}"
  72. end
  73. 1 def standardize_field field
  74. 5200 SQL_FIELD[field.to_sym] || safe_sql(field.to_s)
  75. end
  76. end
  77. end
  78. end

card/lib/card/query/value/match_value.rb

96.77% lines covered

31 relevant lines. 30 lines covered and 1 lines missed.
    
  1. 1 class Card
  2. 1 module Query
  3. 1 class Value
  4. 1 class << self
  5. 1 def match_prefices
  6. 1 @match_prefices ||= %w[= ~]
  7. end
  8. 1 def match_term_and_prefix_re
  9. 40 @match_term_and_prefix_re ||=
  10. /^(?<prefix>[#{Regexp.escape match_prefices.join}]*)\s*(?<term>.*)$/
  11. end
  12. end
  13. # handling for match operator
  14. 1 module MatchValue
  15. 1 def match_sql field
  16. 40 exact_name_match(field) ||
  17. "#{match_field field} #{connection.match match_value}"
  18. end
  19. 1 def exact_name_match field
  20. 40 return false unless match_prefix == "=" && field.to_sym == :name
  21. "#{field_sql field} = #{quote match_term.to_name.key}"
  22. end
  23. 1 def match_field field
  24. 40 fld = field.to_sym == :name ? "name" : standardize_field(field)
  25. 40 "#{@query.table_alias}.#{fld}"
  26. end
  27. 1 def match_value
  28. 40 escape_regexp_characters unless match_prefix == "~~"
  29. 40 quote match_term
  30. end
  31. 1 def match_term
  32. 78 @match_term || (parse_match_term_and_prefix && @match_term)
  33. end
  34. 1 def match_prefix
  35. 80 @match_prefix || (parse_match_term_and_prefix && @match_prefix)
  36. end
  37. # if search val is prefixed with "~~", it is a MYSQL regexp
  38. # (and will be passed through)
  39. #
  40. # Otherwise, all non-alphanumeric characters are escaped.
  41. #
  42. # A "~" prefix is ignored.
  43. 1 def parse_match_term_and_prefix
  44. 40 raw_term = Array.wrap(@value).join(" ")
  45. 40 matches = raw_term.match self.class.match_term_and_prefix_re
  46. 40 @match_prefix = matches[:prefix] || ""
  47. 40 @match_term = matches[:term] || ""
  48. end
  49. 1 def escape_regexp_characters
  50. 38 match_term.gsub!(/(\W)/, '\\\\\1')
  51. end
  52. end
  53. end
  54. end
  55. end

card/lib/card/reference.rb

58.82% lines covered

34 relevant lines. 20 lines covered and 14 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 class Card
  3. # a Reference is a directional relationship from one card (the referer)
  4. # to another (the referee).
  5. 1 class Reference < ApplicationRecord
  6. 1 class << self
  7. # bulk insert improves performance considerably
  8. # array takes form [ [referer_id, referee_id, referee_key, ref_type], ...]
  9. 1 def mass_insert array
  10. 1507 return if array.empty?
  11. 6373 value_statements = array.map { |values| "\n(#{values.join ', '})" }
  12. sql = "INSERT into card_references "\
  13. "(referer_id, referee_id, referee_key, ref_type) "\
  14. 1507 "VALUES #{value_statements.join ', '}"
  15. 1507 Card.connection.execute sql
  16. end
  17. # map existing reference to name to card via id
  18. 1 def map_referees referee_key, referee_id
  19. 2691 where(referee_key: referee_key).update_all referee_id: referee_id
  20. end
  21. # references no longer refer to card, so remove id
  22. 1 def unmap_referees referee_id
  23. 934 where(referee_id: referee_id).update_all referee_id: nil
  24. end
  25. # find all references to missing (eg deleted) cards and reset them
  26. 1 def unmap_if_referee_missing
  27. 1 joins(
  28. "LEFT JOIN cards ON card_references.referee_id = cards.id"
  29. ).where(
  30. "(cards.id IS NULL OR cards.trash IS TRUE) AND referee_id IS NOT NULL"
  31. ).update_all referee_id: nil
  32. end
  33. # remove all references from missing (eg deleted) cards
  34. 1 def delete_if_referer_missing
  35. 1 joins(
  36. "LEFT JOIN cards ON card_references.referer_id = cards.id"
  37. ).where(
  38. "cards.id IS NULL"
  39. ).pluck_in_batches(:id) do |group_ids|
  40. # used to be .delete_all here, but that was failing on large dbs
  41. Rails.logger.info "deleting batch of references"
  42. where("id in (#{group_ids.join ','})").delete_all
  43. end
  44. end
  45. # repair references one by one (delete, create, delete, create...)
  46. # slower, but better than #recreate_all for use on running sites
  47. 1 def repair_all
  48. delete_if_referer_missing
  49. Card.where(trash: false).find_each do |card|
  50. Rails.logger.info "updating references from #{card}"
  51. card.include_set_modules
  52. card.update_references_out
  53. end
  54. end
  55. # delete all references, then recreate them one by one
  56. # faster than #repair_all, but not recommended for use on running sites
  57. 1 def recreate_all
  58. delete_all
  59. Card.where(trash: false).find_each do |card|
  60. Rails.logger.info "updating references from #{card}"
  61. card.include_set_modules
  62. card.create_references_out
  63. end
  64. end
  65. end
  66. # card that refers
  67. 1 def referer
  68. Card[referer_id]
  69. end
  70. # card that is referred to
  71. 1 def referee
  72. Card[referee_id]
  73. end
  74. end
  75. end

card/lib/card/seed_consts.rb

87.5% lines covered

8 relevant lines. 7 lines covered and 1 lines missed.
    
  1. 1 unless defined? CARD_SEED_TABLES
  2. CARD_SEED_TABLES =
  3. 1 %w[cards card_actions card_acts card_changes card_references
  4. schema_migrations schema_migrations_core_cards
  5. schema_migrations_deck schema_migrations_deck_cards].freeze
  6. end
  7. 1 unless defined? CARD_SEED_PATH
  8. 1 CARD_SEED_PATH = File.join(
  9. ENV["CARD_SEED_REPO_PATH"] || [Cardio.gem_root, "db", "seed"], "new"
  10. )
  11. end
  12. 1 unless defined? CARD_TEST_SEED_PATH
  13. CARD_TEST_SEED_PATH = File.join(Cardio.gem_root, "db", "seed", "test", "fixtures")
  14. end
  15. 1 unless defined? CARD_TEST_SEED_SCRIPT_PATH
  16. 1 CARD_TEST_SEED_SCRIPT_PATH = File.join(Cardio.gem_root, "db", "test_seed.rb")
  17. end

card/lib/card/set/type.rb

100.0% lines covered

26 relevant lines. 26 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 module Set
  3. 1 class Type < Pattern::Base
  4. 1 def initialize card
  5. 4406 super
  6. # support type inheritance
  7. 4406 @inherit_card = card unless module_key
  8. end
  9. 1 def lookup_module_list modules_hash
  10. 6019 lookup_key = module_key || inherited_key
  11. 6019 modules_hash[lookup_key] if lookup_key
  12. end
  13. 1 private
  14. 1 def inherited_key
  15. 238 if defined?(@inherited_key)
  16. 35 @inherited_key
  17. else
  18. 203 @inherited_key = lookup_inherited_key
  19. end
  20. end
  21. 1 def lookup_inherited_key
  22. 203 return unless (card = @inherit_card)
  23. 203 @inherit_card = nil
  24. 203 return unless (type_code = default_type_code card)
  25. 203 mod_key = "Type::#{type_code.to_s.camelize}"
  26. 203 mod_key if mods_exist_for_key? mod_key
  27. end
  28. 1 def default_type_code card
  29. 203 card.rule_card(:default)&.type_code
  30. end
  31. 1 def mods_exist_for_key? mod_key
  32. 203 list_of_hashes = Card::Set.modules[:nonbase_format].values
  33. 203 list_of_hashes << Card::Set.modules[:nonbase]
  34. 406 list_of_hashes.any? { |h| h[mod_key] }
  35. end
  36. end
  37. end
  38. end

card/lib/card/subcards.rb

91.07% lines covered

56 relevant lines. 51 lines covered and 5 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 class Card
  3. # API to create/update/delete additional cards together with the main card.
  4. # The most common case is for fields but subcards don't have to be descendants.
  5. #
  6. # Subcards can be added as card objects or attribute hashes.
  7. #
  8. # Use the methods defined in core/set/all/subcards.rb
  9. # Example
  10. # Together with "my address" you want to create the subcards
  11. # "my address+name", "my address+street", etc.
  12. 1 class Subcards
  13. 1 include Add
  14. 1 include Remove
  15. 1 include Relate
  16. 1 attr_accessor :context_card, :keys
  17. 1 def initialize context_card
  18. 2828 @context_card = context_card
  19. 2828 @keys = ::Set.new
  20. end
  21. 1 def [] name
  22. card(name) || field(name)
  23. end
  24. 1 def field name
  25. 60 key = field_name_to_key name
  26. 60 fetch_subcard key if @keys.include? key
  27. end
  28. 1 def card name
  29. 3 return unless @keys.include? name.to_name.key
  30. 3 fetch_subcard name
  31. end
  32. 1 def present?
  33. 40 @keys.present?
  34. end
  35. 1 def catch_up_to_stage stage_index
  36. each_card do |subcard|
  37. subcard.catch_up_to_stage stage_index
  38. end
  39. end
  40. 1 def rename old_name, new_name
  41. 201 return unless @keys.include? old_name.to_name.key
  42. 16 @keys.delete old_name.to_name.key
  43. 16 @keys << new_name.to_name.key
  44. end
  45. 1 def respond_to_missing? method_name, _include_private=false
  46. 3 @keys.respond_to? method_name
  47. end
  48. 1 def method_missing method, *args
  49. 3 return unless respond_to_missing?(method)
  50. 3 @keys.send method, *args
  51. end
  52. # fetch all cards first to avoid side effects
  53. # e.g. deleting a user adds follow rules and +*account to subcards
  54. # for deleting but deleting follow rules can remove +*account from the
  55. # cache if it belongs to the rule cards
  56. 1 def cards
  57. 33174 @keys.map do |key|
  58. 10307 fetch_subcard key
  59. end.compact
  60. end
  61. 1 def each_card
  62. 33174 cards.each do |card|
  63. 10307 yield card
  64. end
  65. end
  66. 1 alias_method :each, :each_card
  67. 1 def each_with_key
  68. 2910 @keys.each do |key|
  69. 379 card = fetch_subcard(key)
  70. 379 yield(card, key) if card
  71. end
  72. end
  73. 1 def fetch_subcard key
  74. 10747 Card.fetch key, local_only: true, new: {}
  75. end
  76. 1 private
  77. 1 def subcard_key cardish
  78. 1 key = case cardish
  79. when Card then cardish.key
  80. when Symbol then fetch_subcard(cardish).key
  81. 1 else cardish.to_name.key
  82. end
  83. 1 key = absolutize_subcard_name(key).key unless @keys.include?(key)
  84. 1 key
  85. end
  86. 1 def absolutize_subcard_name name
  87. 845 name = Card::Name[name]
  88. 845 return name if @context_card.name.parts.first.blank?
  89. 837 name.absolute_name @context_card.name
  90. end
  91. end
  92. end

card/lib/card/subcards/add.rb

88.33% lines covered

60 relevant lines. 53 lines covered and 7 lines missed.
    
  1. 1 class Card
  2. 1 class Subcards
  3. # Methods for adding subcards
  4. 1 module Add
  5. # @example Add a subcard with name 'spoiler'
  6. # add 'spoiler', type: 'Phrase', content: 'John Snow is a Targaryen'
  7. # card_obj = Card.new name: 'spoiler', type: 'Phrase',
  8. # content: 'John Snow is a Targaryen'
  9. # add card_obj
  10. # add name: 'spoiler', type: 'Phrase', content: 'John Snow is a Targaryen'
  11. #
  12. # @example Add a subcard that is added in the integration phase
  13. # (and hence doesn't hold up the transaction for the main card)
  14. # add 'spoiler', content: 'John Snow is a Targaryen'
  15. # add card_obj, delayed: true
  16. 1 def << value
  17. add value
  18. end
  19. 1 def []= name, card_or_attr
  20. case card_or_attr
  21. when Hash
  22. new_by_attributes name, card_or_attr
  23. when Card
  24. new_by_card card_or_attr
  25. end
  26. end
  27. 1 def add *args
  28. 2465 case args.first
  29. 984 when Card then new_by_card args.first
  30. 984 when Hash then add_hash args.first
  31. 497 else new_by_attributes(*args)
  32. end
  33. end
  34. 1 def add_hash hash
  35. 984 if (name = hash.delete :name)
  36. 2 new_by_attributes name, hash
  37. else
  38. 982 multi_add hash
  39. end
  40. end
  41. 1 def add_child name, args
  42. 97 name = name.is_a?(Symbol) ? name.cardname : name.to_name
  43. 97 add name.prepend_joint, args
  44. end
  45. 1 alias_method :add_field, :add_child
  46. 1 def new_by_card card
  47. 1829 card.supercard = @context_card
  48. 1829 if !card.name.simple? && card.name.field_of?(@context_card.name)
  49. 771 card.superleft = @context_card
  50. end
  51. 1829 @keys << card.key
  52. 1829 Card.write_to_soft_cache card
  53. 1829 card.director = @context_card.director.subdirectors.add card
  54. 1829 card
  55. end
  56. 1 def new_by_attributes name, attributes={}
  57. 845 attributes ||= {}
  58. 845 absolute_name = absolutize_subcard_name name
  59. 845 subcard_args = extract_subcard_args! attributes
  60. 845 card = initialize_by_attributes absolute_name, attributes
  61. 845 subcard = new_by_card card
  62. 845 card.subcards.add subcard_args
  63. 845 subcard
  64. end
  65. 1 def initialize_by_attributes name, attributes
  66. 845 Card.assign_or_newish name, attributes, local_only: true
  67. end
  68. # TODO: this method already exists as card instance method in
  69. # tracked_attributes.rb. Find a place for it where its accessible
  70. # for both. There is one important difference. The keys are symbols
  71. # here instead of strings
  72. 1 def extract_subcard_args! args
  73. 845 subcards = args.delete(:subcards) || {}
  74. 845 if (subfields = args.delete(:subfields))
  75. 1 subfields.each_pair do |key, value|
  76. 1 subcards[normalize_subfield_key(key)] = value
  77. end
  78. end
  79. 845 args.keys.each do |key|
  80. 518 subcards[key] = args.delete(key) if key =~ /^\+/
  81. end
  82. 845 subcards
  83. end
  84. 1 private
  85. # ensure a leading '+'
  86. 1 def normalize_subfield_key key
  87. 1 key = Card::Codename.name(key) if key.is_a?(Symbol) && Card::Codename.exist?(key)
  88. 1 key.to_name.prepend_joint
  89. end
  90. # Handles hash with several subcards
  91. 1 def multi_add args
  92. 982 args.each_pair do |key, val|
  93. 346 case val
  94. when String, Array, Integer
  95. 240 new_by_attributes key, content: val
  96. when Card
  97. val.name = absolutize_subcard_name key
  98. new_by_card val
  99. when nil
  100. next
  101. else
  102. 106 new_by_attributes key, val
  103. end
  104. end
  105. end
  106. end
  107. end
  108. end

card/lib/card/subcards/relate.rb

92.86% lines covered

14 relevant lines. 13 lines covered and 1 lines missed.
    
  1. 1 class Card
  2. 1 class Subcards
  3. # Methods for handling related subcards
  4. 1 module Relate
  5. 1 def field_name_to_key name
  6. 60 if @context_card.name.starts_with_joint?
  7. relative_child(name).key
  8. else
  9. 60 child(name).key
  10. end
  11. end
  12. 1 def child name
  13. 60 absolute_name = @context_card.name.field_name name
  14. 60 if @keys.include? absolute_name.key
  15. 57 absolute_name
  16. else
  17. 3 relative_child name
  18. end
  19. end
  20. 1 def relative_child name
  21. 3 @context_card.name.relative_field_name name
  22. end
  23. end
  24. end
  25. end

card/lib/card/subcards/remove.rb

66.67% lines covered

27 relevant lines. 18 lines covered and 9 lines missed.
    
  1. 1 class Card
  2. 1 class Subcards
  3. # Methods for removing/clearing subcards
  4. 1 module Remove
  5. 1 def remove_child cardish
  6. child = cardish.is_a?(Card) ? cardish : child(cardish)
  7. remove child
  8. end
  9. 1 alias_method :remove_field, :remove_child
  10. 1 def remove name_or_card
  11. 1 key = subcard_key name_or_card
  12. 1 return unless @keys.include? key
  13. 1 @keys.delete key
  14. 1 clear_key key
  15. end
  16. 1 def clear
  17. @keys.each { |key| clear_key key }
  18. @keys = ::Set.new
  19. end
  20. 1 def clear_key key
  21. 1 if (subcard = fetch_subcard key)
  22. 1 Director.deep_delete subcard.director
  23. 1 subcard.current_action&.delete
  24. end
  25. 1 Card.cache.soft.delete key
  26. 1 subcard
  27. end
  28. 1 def deep_clear cleared=::Set.new
  29. each_card do |card|
  30. next if cleared.include? card.id
  31. cleared << card.id
  32. card.subcards.deep_clear cleared
  33. end
  34. clear
  35. end
  36. end
  37. end
  38. end

card/lib/card/version.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 class Card
  3. 1 module Version
  4. 1 class << self
  5. 1 def release
  6. 31 @@version ||= File.read(File.expand_path("../../VERSION", __dir__)).strip
  7. end
  8. end
  9. end
  10. end

card/lib/card/view.rb

93.18% lines covered

44 relevant lines. 41 lines covered and 3 lines missed.
    
  1. 1 class Card
  2. # Card::View manages {Options view options}, {Cache view caching}, and
  3. # {Permission view permissions}.
  4. #
  5. # View objects, which are instantiated whenever a view is rendered, are available as
  6. # in views and other format methods. The view objects can be accessed using `#voo`.
  7. # We sometimes feebly pretend VOO is an acronym for "view option object," but really
  8. # we just needed a way not to confuse these Card::View options with the countless
  9. # references to viewnames that naturally arise when rendering views within views within
  10. # views.
  11. #
  12. # When view A renders view B within the same format object, A's voo is the parent of
  13. # B's voo. When card C nests card D, a new (sub)format object is initialized. C is then
  14. # the parent _format_ of D, but D has its own root voo.
  15. #
  16. # So a lineage might look something like this:
  17. #
  18. # `F1V1 -> F1V2 -> F1V3 -> F2V1 -> F2V2 -> F3V1 ...`
  19. #
  20. #
  21. 1 class View
  22. 1 include Options
  23. 1 include View::Cache
  24. 1 include Classy
  25. 1 include Permission
  26. 1 extend View::Cache::ClassMethods
  27. 1 attr_reader :format, :parent, :card
  28. 1 class << self
  29. # @return [Symbol] viewname as Symbol
  30. 1 def normalize view
  31. 28904 view.present? ? view.to_sym : nil
  32. end
  33. # @return [Array] list of viewnames as Symbols
  34. 1 def normalize_list val
  35. 44577 case val
  36. 44410 when NilClass then []
  37. 23 when Array then val
  38. 20 when String then val.split(/[\s,]+/)
  39. 124 when Symbol then [val]
  40. else raise Card::Error, "bad show/hide argument: #{val}"
  41. end
  42. end
  43. end
  44. # @param format [Card::Format]
  45. # @param view [Symbol] viewname. Note: Card::View is initialized without a view
  46. # when `voo` is called outside of a render,
  47. # eg `subformat(cardname).method_with_voo_reference`.
  48. # @param raw_options [Hash]
  49. # @param parent [Card::View] (optional)
  50. 1 def initialize format, view, raw_options={}, parent=nil
  51. 20912 @format = format
  52. 20912 @raw_view = view
  53. 20912 @raw_options = raw_options
  54. 20912 @parent = parent
  55. 20912 @card = @format.card
  56. 20912 normalize_options
  57. end
  58. # handle rendering, including optional visibility, permissions, and caching
  59. # @return [rendered view or a stub]
  60. 1 def process
  61. 20887 return if process_live_options == :hide
  62. 40335 fetch { yield ok_view }
  63. end
  64. # the view to "attempt". Typically the same as @raw_view, but @raw_view can
  65. # be overridden, eg for the main view (top view of the main card on a page)
  66. # @return [Symbol] view name
  67. 1 def requested_view
  68. 162288 @requested_view ||= View.normalize live_options[:view]
  69. end
  70. # the final view. can be different from @requested_view when there are
  71. # issues with permissions, recursions, unknown cards, etc.
  72. # @return [Symbol] view name
  73. 1 def ok_view
  74. 60540 @ok_view ||= format.monitor_depth { altered_view || requested_view }
  75. end
  76. # @return [Card::View]
  77. 1 def root
  78. @root = parent ? parent.root : self
  79. end
  80. # @return [true/false]
  81. 1 def root?
  82. 4 !parent
  83. end
  84. # the root voo of the root format
  85. 1 def deep_root
  86. format.root.voo
  87. end
  88. # neither view nor format has a parent
  89. # @return [true/false]
  90. 1 def deep_root?
  91. 19 !parent && !format.parent
  92. end
  93. # next voo object found tracing ancestry through parent voos and/or parent formats
  94. # @return [Card::View]
  95. 1 def next_ancestor across_format=true
  96. 164 parent || (across_format && next_format_ancestor) || nil
  97. end
  98. # voo object of format's parent
  99. 1 def next_format_ancestor
  100. 10112 format.parent&.voo
  101. end
  102. end
  103. end

card/lib/card/view/cache.rb

89.29% lines covered

56 relevant lines. 50 lines covered and 6 lines missed.
    
  1. 1 class Card
  2. 1 class View
  3. # View::Cache supports smart card view caching.
  4. #
  5. # The basic idea is that when view caching is turned on (via `config.view_cache`),
  6. # we try to cache a view whenever it's "safe" to do so. We will include everything
  7. # inside that view (including other views) until we find something that isn't safe.
  8. # When something isn't safe, we render a {Stub stub}: a placeholder
  9. # with all the info we need to come back and replace it with the correct content
  10. # later. In this way it is possible to have many levels of cached views within
  11. # cached views.
  12. #
  13. # Here are some things that we never consider safe to cache:
  14. #
  15. # 1. a view explicitly configured _never_ to be cached
  16. # 2. a view of a card with view-relevant permission restrictions
  17. # 3. a view other than the requested view (eg a denial view)
  18. # 4. a card with unsaved content changes
  19. #
  20. # We also consider it unsafe to cache a view of one card within a view of a different
  21. # card, so nests are always handled with a stub.
  22. #
  23. # ## Cache configuration
  24. #
  25. # Cache settings (#5) can be configured in the
  26. # {Set::Format::AbstractFormat#view view definition}
  27. # and (less commonly) as a {Card::View::Options view option}.
  28. #
  29. # By far, the most common explicit caching configuration is `:never`. This setting
  30. # is used to prevent over-caching, which becomes problematic when data changes
  31. # do not clear the cache.
  32. #
  33. # Generally speaking, a card is smart about clearing its own view caches when
  34. # anything about the card itself. So when I update the card "Johnny", all the cached
  35. # views of "Johnny" are cleared. Similarly, changes to structure rules and other
  36. # basic patterns are typically well managed by the caching system.
  37. #
  38. # However, there are many other potential changes that views cannot detect. Views that
  39. # are susceptible to these "cache hazards" should be configured with `cache: :never`.
  40. #
  41. # ## Cache hazards
  42. #
  43. # If a view contains any of the following cache hazards, it would be wise to consider
  44. # a `cache: :never` configuration:
  45. #
  46. # - dynamic searches (eg `Card.search`) whose results may change
  47. # - live timestamps (eg `Time.now`)
  48. # - environmental variables (eg `Env.params`)
  49. # - any variables altered in one view and used in another (eg `@myvar`)
  50. # - other cards' properties (eg `Card["random"].content`)
  51. #
  52. # What all of the above have in common is that they involve changes about which the
  53. # view caching system is unaware. This means that whether the cache hazard is
  54. # rendered directly in a view or just used in its logic, it can change in a way
  55. # that _should_ change the view but _won't_ change the view if it's cached.
  56. #
  57. # ## Altering cached views
  58. #
  59. # Whereas ignoring cache hazards may cause over-caching, altering cached views
  60. # may cause outright errors. If a view directly alters a rendered view,
  61. # it may be dangerous to cache.
  62. #
  63. # # obviously safe to cache
  64. # view(:x) { "ABC" }
  65. #
  66. # # also safe, because x is NOT altered
  67. # view(:y) { render_x + "DEF" }
  68. #
  69. # # unsafe and thus never cached, because x is altered
  70. # view(:z, cache: :never) { render_x.reverse }
  71. #
  72. # Specifically, the danger is that the inner view will be rendered as a stub,
  73. # and the out view will end up altering the stub and not the view.
  74. #
  75. # Although alterations should be considered dangerous, they are actually only
  76. # problematic in situations where the inner view might sometimes render a stub.
  77. # If the outer view is rendering a view of the _same card_ with all the _same view
  78. # settings_ (perms, unknown, etc), there will be no stub and thus no error.
  79. # Remember, however, that a view on a narrow set may inherit view settings
  80. # from a general set. To be confident that a view alteration is safe, all inherited
  81. # settings must be taken into account.
  82. #
  83. # ## Caching Best Practices
  84. #
  85. # Here are some good rules of thumb to make good use of view caching:
  86. #
  87. # 1. *Use nests.* If you can show the content of a different card with a nest rather
  88. # than by showing the content directly, the caching system will be much
  89. # happier with you.
  90. #
  91. # view :bad_idea, cache: :never do
  92. # Card["random"].content
  93. # end
  94. #
  95. # view :good_idea do
  96. # nest :random, view: :core
  97. # end
  98. #
  99. # 2. *Isolate the cache hazards.* Consider the following variants:
  100. #
  101. # view :bad_idea, cache: :never do
  102. # if morning_for_user?
  103. # expensive_good_morning
  104. # else
  105. # expensive_good_afternoon
  106. # end
  107. # end
  108. #
  109. # view :good_idea, cache: :never do
  110. # morning_for_user? ? render_good_morning : render_good_afternoon
  111. # end
  112. #
  113. # In the first example, we have to generate expensive greetings every time we
  114. # render the view. In the second, only the test is not cached.
  115. #
  116. # 3. If you must alter view results, consider *generating the view content
  117. # in a separate method.*
  118. #
  119. # # First Attempt
  120. #
  121. # view :hash_it_in do
  122. # { cool: false }
  123. # end
  124. #
  125. # view :bad_idea, cache: :never do
  126. # render_badhash.merge sucks: true
  127. # end
  128. #
  129. #
  130. # #Second Attempt
  131. #
  132. # view :hash_it_out do
  133. # hash_it_out
  134. # end
  135. #
  136. # def hash_it_out
  137. # { cool: true }
  138. # end
  139. #
  140. # view :good_idea do
  141. # hash_it_out.merge rocks: true
  142. # end
  143. #
  144. # The first attempt will work fine with caching off but is risky with caching on.
  145. # The second is safe with caching on.
  146. #
  147. # ## Optimizing with `:always`
  148. #
  149. # It is never strictly necessary to use `cache: :always`, but this setting can help
  150. # optimize your use of the caching system in some cases.
  151. #
  152. # Consider the following views:
  153. #
  154. # view(:hat) { "hat" } # ...but imagine this is computationally expensive
  155. #
  156. # view(:old_hat) { "old #{render_hat}" }
  157. # view(:new_hat) { "new #{render_hat}" }
  158. # view(:red_hat) { "red #{render_hat}" }
  159. # view(:blue_hat) { "blue #{render_hat}" }
  160. #
  161. # Whether "hat" uses `:standard` or `:always`, the hat varieties (old, new, etc...)
  162. # will fully contain the rendered hat view in their cache. However, with `:standard`,
  163. # the other views will each re-render hat without attempting to cache it separately
  164. # or to find it in the cache. This could lead to man expensive renderings of the
  165. # "hat" view. By contrast, if the cache setting is `:always`, then hat will be
  166. # cached and retrieved even when it's rendered inside another cached view.
  167. #
  168. 1 module Cache
  169. 1 require "card/view/cache/cache_action"
  170. 1 require "card/view/cache/stub"
  171. 1 include CacheAction
  172. 1 include Stub
  173. 1 private
  174. # render or retrieve view (or stub) with current options
  175. # @param block [Block] code block to render
  176. # @return [rendered view or stub]
  177. 1 def fetch &block
  178. 20168 case cache_action
  179. 20167 when :yield then yield # simple render
  180. 1 when :cache_yield then cache_render(&block) # render to/from cache
  181. when :stub then stub # render stub
  182. end
  183. end
  184. # Fetch view via cache and, when appropriate, render its stubs
  185. #
  186. # If this is a free cache action (see CacheAction), we go through the stubs and
  187. # render them now.
  188. # If the cache is active (ie, we are inside another view), we do not worry about
  189. # stubs but keep going, because the free cache we're inside will take care of
  190. # those stubs.
  191. #
  192. # @return [String (usually)] rendered view
  193. 1 def cache_render
  194. 1 cached_view = cache_fetch { yield }
  195. 1 cache_active? ? cached_view : format.stub_render(cached_view)
  196. end
  197. # Is there already a view cache in progress on which this one depends?
  198. #
  199. # Note that if you create a brand new independent format object
  200. # (ie, not a subformat)
  201. # its activity will be treated as unrelated to this caching/rendering.
  202. #
  203. # @return [true/false]
  204. 1 def cache_active?
  205. 19 deep_root? ? false : self.class.caching?
  206. end
  207. # If view is cached, retrieve it. Otherwise render and store it.
  208. # Uses the primary cache API.
  209. 1 def cache_fetch
  210. 1 caching do
  211. 1 ensure_cache_key
  212. 1 self.class.cache.fetch cache_key do
  213. yield
  214. end
  215. end
  216. end
  217. # keep track of nested cache fetching
  218. 1 def caching
  219. 2 self.class.caching(self) { yield }
  220. end
  221. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  222. # VIEW CACHE KEY
  223. 1 def cache_key
  224. 2 @cache_key ||= [
  225. card_cache_key, format.class, format.nest_mode, options_for_cache_key
  226. ].map(&:to_s).join "-"
  227. end
  228. 1 def card_cache_key
  229. 1 card.real? ? card.id : "#{card.key}-#{card.type_id}"
  230. end
  231. # Registers the cached view for later clearing in the event of related card changes
  232. 1 def ensure_cache_key
  233. 1 card.ensure_view_cache_key cache_key
  234. end
  235. 1 def options_for_cache_key
  236. 1 hash_for_cache_key(live_options) + hash_for_cache_key(viz_hash)
  237. end
  238. 1 def hash_for_cache_key hash
  239. 2 hash.keys.sort.map do |key|
  240. 6 option_for_cache_key key, hash[key]
  241. end.join ";"
  242. end
  243. 1 def array_for_cache_key array
  244. # TODO: needs better handling of edit_structure
  245. # currently we pass complete structure as nested array
  246. array.map do |item|
  247. item.is_a?(Array) ? item.join(":") : item.to_s
  248. end.sort.join ","
  249. end
  250. 1 def option_for_cache_key key, value
  251. 6 "#{key}:#{option_value_to_string value}"
  252. end
  253. 1 def option_value_to_string value
  254. 6 case value
  255. when Hash then "{#{hash_for_cache_key value}}"
  256. when Array then array_for_cache_key(value)
  257. 6 else value.to_s
  258. end
  259. end
  260. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  261. # cache-related Card::View class methods
  262. 1 module ClassMethods
  263. 1 def cache
  264. 4 Card::Cache[Card::View]
  265. end
  266. 1 def caching?
  267. 17 !@caching.nil?
  268. end
  269. 1 def caching voo
  270. 1 old_caching = @caching
  271. 1 @caching = voo
  272. 1 yield
  273. ensure
  274. 1 @caching = old_caching
  275. end
  276. end
  277. end
  278. end
  279. end

card/lib/card/view/cache/cache_action.rb

72.73% lines covered

44 relevant lines. 32 lines covered and 12 lines missed.
    
  1. 1 class Card
  2. 1 class View
  3. 1 module Cache
  4. # determine action to be used in #fetch
  5. 1 module CacheAction
  6. 1 private
  7. # course of action based on config/status/options
  8. # @return [Symbol] :yield, :cache_yield, or
  9. 1 def cache_action
  10. 20168 log_cache_action do
  11. 20168 send "#{cache_status}_cache_action"
  12. end
  13. end
  14. 1 def log_cache_action
  15. 20168 action = yield
  16. # TODO: make configurable
  17. # ...or better yet, integrate into performance logger...
  18. # Rails.logger.warn "VIEW CACHE #{cache_active? ? '-->' : ''}[#{action}] "\
  19. # "(#{card.name}##{requested_view})"
  20. 20168 action
  21. end
  22. # @return [Symbol] :off, :active, or :free
  23. 1 def cache_status
  24. case
  25. 20168 when !cache_on?
  26. 20150 :off # view caching is turned off, format- or system-wide
  27. when cache_active?
  28. :active # another view cache is in progress (current view is inside it)
  29. else
  30. 18 :free # no other cache in progress
  31. end
  32. end
  33. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  34. # CACHE STATUS: OFF
  35. # view caching is turned off, format- or system-wide
  36. # @return [True/False]
  37. 1 def cache_on?
  38. 20168 Card.config.view_cache && format.class.view_caching?
  39. end
  40. # always skip all the magic
  41. 1 def off_cache_action
  42. 20150 :yield
  43. end
  44. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  45. # CACHE STATUS: FREE
  46. # caching is on; no other cache in progress
  47. # @return [Symbol]
  48. 1 def free_cache_action
  49. 18 free_cache_ok? ? :cache_yield : :yield
  50. end
  51. # @return [True/False]
  52. 1 def free_cache_ok?
  53. 18 cache_setting != :never && clean_enough_to_cache?
  54. end
  55. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  56. # CACHE STATUS: ACTIVE
  57. # another view cache is in progress; this view is inside it
  58. # @return [Symbol]
  59. 1 def active_cache_action
  60. active_cache_ok? ? active_cache_action_from_setting : :stub
  61. end
  62. # @return [True/False]
  63. 1 def active_cache_ok?
  64. return false unless parent && clean_enough_to_cache?
  65. return true if normalized_options[:skip_perms]
  66. active_cache_permissible?
  67. end
  68. # apply any permission checks required by view.
  69. # (do not cache views with nuanced permissions)
  70. 1 def active_cache_permissible?
  71. case view_perms
  72. when :none then true
  73. when parent.view_perms then true
  74. when Symbol then format.anyone_can?(view_perms)
  75. else false
  76. end
  77. end
  78. # determine the cache action from the cache setting
  79. # (assuming cache status is "active")
  80. # @return [Symbol] cache action
  81. 1 def active_cache_action_from_setting
  82. level = ACTIVE_CACHE_LEVEL[cache_setting]
  83. level || raise("unknown cache setting: #{cache_setting}")
  84. end
  85. ACTIVE_CACHE_LEVEL =
  86. 1 { always: :cache_yield, standard: :yield, never: :stub }.freeze
  87. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  88. # SHARED METHODS
  89. # @return [Symbol] :standard, :always, or :never
  90. 1 def cache_setting
  91. 18 format.view_cache_setting requested_view
  92. end
  93. # altered view requests and altered cards are not cacheable
  94. # @return [True/False]
  95. 1 def clean_enough_to_cache?
  96. # requested_view == ok_view && !card.unknown? && !card.db_content_changed?
  97. 5 requested_view == ok_view && card.view_cache_clean?
  98. end
  99. end
  100. end
  101. end
  102. end

card/lib/card/view/cache/stub.rb

60.0% lines covered

15 relevant lines. 9 lines covered and 6 lines missed.
    
  1. 1 class Card
  2. 1 class View
  3. 1 module Cache
  4. # A "stub" is a placeholder for a card view.
  5. #
  6. # Cached views use stubs so that _nesting_ content can remained cached
  7. # even while _nested_ content changes. The nested content's place is held
  8. # by a stub.
  9. #
  10. # A stub must contain all the information necessary to produce the view as intended.
  11. 1 module Stub
  12. 1 private
  13. # @return [String]
  14. 1 def stub
  15. "(StUb#{stub_hash.to_json}sTuB)".html_safe
  16. end
  17. 1 def bin_to_hex string
  18. string.unpack("H*").first
  19. end
  20. # @return [Hash]
  21. 1 def stub_hash
  22. { cast: stub_cast,
  23. view_opts: normalized_options.merge(normalized_visibility_options),
  24. format_opts: { nest_mode: format.nest_mode,
  25. override: root?,
  26. context_names: format.context_names } }
  27. # nest mode handling:
  28. #
  29. # Typically modes override views on nests, but stubs create non-standard nests.
  30. # Mode-based view overrides should NOT apply to standard render calls that have
  31. # been replaced with stubs - only to standard nest calls. The override value
  32. # is used to retain this distinction.
  33. end
  34. 1 def stub_cast
  35. cast = card.cast
  36. cast.delete :content if cast[:content].nil?
  37. cast
  38. end
  39. end
  40. end
  41. end
  42. end

card/lib/card/view/classy.rb

78.26% lines covered

69 relevant lines. 54 lines covered and 15 lines missed.
    
  1. 1 class Card
  2. 1 class View
  3. # API to change css classes in other places
  4. 1 module Classy
  5. # Add additional css classes to a css class
  6. #
  7. # Example
  8. # class_up "card-slot", "card-dark text-muted"
  9. #
  10. # If a view later adds the css "card-slot" to a html tag with
  11. #
  12. # classy("card-slot")
  13. #
  14. # then all additional css classes will be added.
  15. #
  16. # The scope when these additional classes apply can be restricted
  17. # @param klass [String, Symbol] the css class to be enriched with additional classes
  18. # @param classier [String, Array<String>] additional css classes
  19. # @param scope [Symbol]
  20. # :view only in the same view
  21. # :subviews the same and all subviews; not in nests or where its nested
  22. # :format all views, sub and parent views; not in nests or where its nested
  23. # :nests the same as :format but also in nests
  24. # :single_use the same as :nests but is removed after the first use
  25. # :global always everywhere
  26. 1 def class_up klass, classier, scope=:subviews
  27. 876 klass = klass.to_s
  28. 876 storage_voo(scope).add_extra_classes klass, classier, scope
  29. end
  30. 1 def class_down klass, classier
  31. 101 remove_extra_classes klass, classier, :private
  32. end
  33. 1 def with_class_up klass, classier, scope=:subviews
  34. 101 class_up klass, classier, scope
  35. 101 yield
  36. ensure
  37. 101 class_down klass, classier
  38. end
  39. # don't use in the given block the additional class that
  40. # was added to `klass`
  41. 1 def without_upped_class klass
  42. tmp_class = class_list.delete klass
  43. result = yield tmp_class
  44. class_list[klass] = tmp_class
  45. result
  46. end
  47. 1 def classy *classes
  48. 3550 classes = Array.wrap(classes).flatten
  49. 3550 [classes, extra_classes(classes)].flatten.compact.join " "
  50. end
  51. 1 def add_extra_classes key, classier, scope
  52. 876 type = class_list_type scope
  53. 876 class_list(type)[key] =
  54. [class_list(type)[key], classier].flatten.compact.join(" ")
  55. end
  56. # remove classes everywhere where they are visible for the given scope
  57. 1 def remove_extra_classes klass, classier, type
  58. # TODO: scope handling
  59. # Method is not used and maybe no longer necessary with the scope feature
  60. # for class_up.
  61. # It's no longer sufficient to remove only public classes for ancestors.
  62. # Needs an approach similar to extra_classes with the "space" argument
  63. 164 next_ancestor&.remove_extra_classes klass, classier, :public
  64. 164 cl = class_list type
  65. 164 return unless cl[klass]
  66. if cl[klass] == classier
  67. cl.delete klass
  68. else
  69. cl[klass].gsub!(/#{classier}\s?/, "")
  70. end
  71. end
  72. 1 def extra_classes klass
  73. 3550 klass = klass.first if klass.is_a?(Array)
  74. 3550 klass = klass.to_s
  75. 3550 deep_extra_classes klass, :self
  76. end
  77. # recurse through voos and formats to find all extra classes
  78. # @param space [:self, :self_format, :ancestor_format]
  79. 1 def deep_extra_classes klass, space
  80. 22201 [self_extra_classes(klass, space),
  81. ancestor_extra_classes(klass, space)].flatten.compact
  82. end
  83. 1 private
  84. 1 def ancestor_extra_classes klass, space
  85. 22201 if parent
  86. 12237 parent_space = space == :self ? :self_format : :ancestor_format
  87. 12237 parent.deep_extra_classes(klass, parent_space)
  88. else
  89. 9964 next_format_ancestor&.deep_extra_classes(klass, :ancestor_format)
  90. end
  91. end
  92. 1 def storage_voo scope
  93. # When we climb up the voo tree and cross a nest boundary then we can jump only
  94. # to the root voo of the parent format. Hence we have to add classes to the root
  95. # if we want them to be found by nests.
  96. 876 case scope
  97. 876 when :view, :subviews then self
  98. when :format, :nests, :single_use then root
  99. when :global then deep_root
  100. else
  101. raise ArgumentError, "invalid class_up scope: #{scope}"
  102. end
  103. end
  104. 1 def self_extra_classes klass, space
  105. 53691 classes = ok_types(space).map { |ot| class_list(ot)[klass] }
  106. 22201 return classes unless class_list(:single_use)&.key? klass
  107. [classes, class_list(:single_use).delete(klass)]
  108. end
  109. 1 def ok_types space
  110. 22201 case space
  111. 16462 when :ancestor_format then [:public]
  112. 2189 when :self_format then %i[public format_private]
  113. 3550 when :self then %i[public format_private private]
  114. end
  115. end
  116. 1 def class_list type=:private
  117. 55607 case type
  118. when :private, :format_private, :public, :single_use
  119. 55607 @class_list ||= {}
  120. 55607 @class_list[type] ||= {}
  121. else
  122. raise ArgumentError, "#{type} not a valid class list"
  123. end
  124. end
  125. # Translates scopes to the privacy types used to manage the class lists.
  126. # A #classy calls looks in the following class_lists:
  127. # private - only in the same voo
  128. # format_private - the same voo and all parent voos in the same format
  129. # public - in all voos in all parent formats
  130. 1 def class_list_type scope
  131. 876 case scope
  132. when :view
  133. 1 :private
  134. when :format, :subviews
  135. 875 :format_private
  136. when :nests, :global
  137. :public
  138. when :single_use
  139. :single_use
  140. else
  141. raise ArgumentError, "invalid class_up scope: #{scope}"
  142. end
  143. end
  144. end
  145. end
  146. end

card/lib/card/view/options.rb

100.0% lines covered

15 relevant lines. 15 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 class View
  3. # Manages options for rendering card views
  4. #
  5. # Many options are available to sharks via nests. (See https://decko.org/Nest_Syntax)
  6. #
  7. # {{cardname|hide:menu}}
  8. #
  9. # These options and others are available to monkeys when rendering views
  10. # via #render or #nest.
  11. #
  12. # nest "cardname", hide: :menu
  13. # render :viewname, hide: :menu
  14. #
  15. 1 module Options
  16. # the keymap represents a 2x2 matrix, where the factors are
  17. # (a) whether an option's value can be set by a shark via nests, and
  18. # (b) whether subviews can inherit the option from a parent view.
  19. #
  20. # for sharks | not for sharks
  21. # ________________________________
  22. # inherit | both | heir
  23. # don't inherit | shark | none
  24. #
  25. # (note: each option will likely some day merit its own object)
  26. @keymap = {
  27. 1 shark: [
  28. :view, # view to render
  29. :nest_name, # name as used in nest
  30. :nest_syntax, # full nest syntax
  31. :wrap, # wrap the nest with a wrapper
  32. :show, # render these views when optional
  33. :hide # do not render these views when optional
  34. ], # show/hide can be view (Symbol), list of views (Array),
  35. # or comma separated views (String)
  36. # NOTE: although show and hide are in this non-inheriting group, they are
  37. # actually inherited, just not through the standard mechanism. Because, well,
  38. # they're weird. (See process_visibility)
  39. heir: [
  40. :main, # format object is page's "main" object (Boolean)
  41. :home_view, # view for slot to return to when no view specified
  42. :edit_structure, # use a different structure for editing (Array)
  43. :cql, # contextual cql alterations for search cards (Hash)
  44. :action_id, # a Card::Action id (Integer)
  45. :content_opts # options for Card::Content.new
  46. # :context_names # names used to contextualize titles
  47. ],
  48. both: [
  49. :help, # cue text when editing
  50. :structure, # overrides the content of the card
  51. :title, # overrides the name of the card
  52. :variant, # override the canonical version of the name with a different
  53. # variant
  54. :input_type, # inline_nests makes a form within standard content (Symbol)
  55. :type, # set the default type of new cards
  56. :size, # set an image size
  57. # (also used for character limit in one_line_content)
  58. :params, # parameters for add button. deprecated!
  59. :items, # options for items (Hash)
  60. :cache, # change view cache behaviour
  61. # (Symbol<:always, :standard, :never>)
  62. :edit, # edit mode
  63. # (Symbol<:inline, :standard, :full>)
  64. :separator, # item separator in certain lists
  65. :filter
  66. ],
  67. none: [
  68. :skip_perms, # do not check permissions for this view (Boolean)
  69. :main_view, # this is main view of page (Boolean)
  70. :layout #
  71. ]
  72. }
  73. # Note: option values are strings unless otherwise noted
  74. 1 class << self
  75. 1 attr_reader :keymap
  76. 1 def add_option name, type
  77. 1 raise "invalid option type: #{type}" unless @keymap.key?(type)
  78. 1 @keymap[type] << name
  79. 1 reset_key_lists
  80. 1 VooApi.define_getter name
  81. 1 VooApi.define_setter name
  82. end
  83. end
  84. 1 extend KeyLists
  85. 1 include VooApi
  86. 1 include Visibility
  87. end
  88. end
  89. end

card/lib/card/view/options/key_lists.rb

100.0% lines covered

18 relevant lines. 18 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 class View
  3. 1 module Options
  4. 1 module KeyLists
  5. # all standard option keys
  6. # @return [Array]
  7. 1 def all_keys
  8. 55357 @all_keys ||= keymap.each_with_object([]) { |(_k, v), a| a.push(*v) }
  9. end
  10. # keys whose values can be set by Sharks in card nests
  11. # @return [Array]
  12. 1 def shark_keys
  13. 2941 @shark_keys ||= ::Set.new(keymap[:both]) + keymap[:shark]
  14. end
  15. # keys that follow simple standard inheritance pattern from parent views
  16. # @return [Array]
  17. 1 def heir_keys
  18. 11802 @heir_keys ||= ::Set.new(keymap[:both]) + keymap[:heir]
  19. end
  20. # Keys that can be read or written via accessors
  21. # @return [Array]
  22. 1 def accessible_keys
  23. 3 all_keys - [ # (all but the following)
  24. :view, # view is accessed as requested_view or ok_view and cannot be
  25. # directly manipulated
  26. :show, :hide # these have a more extensive API (see Card::View::Visibility)
  27. ]
  28. end
  29. 1 def slot_keys
  30. 907 @slot_keys ||= all_keys - [:skip_perms]
  31. end
  32. 1 def reset_key_lists
  33. 1 @all_keys = nil
  34. 1 @shark_keys = nil
  35. 1 @heir_keys = nil
  36. end
  37. end
  38. end
  39. end
  40. end

card/lib/card/view/options/visibility.rb

93.18% lines covered

44 relevant lines. 41 lines covered and 3 lines missed.
    
  1. 1 class Card
  2. 1 class View
  3. 1 module Options
  4. # manages showing and hiding optional view renders
  5. 1 module Visibility
  6. # tracks show/hide value for each view with an explicit setting
  7. # eg { toggle: :hide }
  8. 1 def viz_hash
  9. 113322 @viz_hash ||= {}
  10. end
  11. # test methods
  12. 1 def hide? view
  13. 21869 viz_hash[view&.to_sym] == :hide
  14. end
  15. 1 def show? view
  16. 1174 !hide? view
  17. end
  18. # write methods
  19. 1 def show *views
  20. 105 viz views, :show
  21. end
  22. 1 def hide *views
  23. 619 viz views, :hide
  24. end
  25. # force write methods
  26. 1 def show! *views
  27. 11 viz views, :show, true
  28. end
  29. 1 def hide! *views
  30. 467 viz views, :hide, true
  31. end
  32. # advanced write method
  33. 1 VIZ_SETTING = { show: :show, true => :show,
  34. hide: :hide, false => :hide, nil => :hide }.freeze
  35. 1 def viz views, setting, force=false
  36. 65630 Array.wrap(views).flatten.each do |view|
  37. 21522 view = view.to_sym
  38. 21522 next if !force && viz_hash[view]
  39. 21451 viz_hash[view] = VIZ_SETTING[setting]
  40. end
  41. end
  42. 1 def visible? view
  43. 77 viz view, yield unless viz_hash[view]
  44. 77 show? view
  45. end
  46. # test whether view is optional
  47. # (@optional is set in normalize_options
  48. # @return [true/false]
  49. 1 def optional?
  50. 20902 @optional
  51. end
  52. # translate raw hide, show options (which can be strings, symbols,
  53. # arrays, etc)
  54. 1 def process_visibility
  55. 22282 viz_hash.reverse_merge! parent.viz_hash if parent
  56. 22282 process_visibility_options live_options
  57. 22282 viz requested_view, @optional if @optional && !viz_hash[requested_view]
  58. end
  59. 1 private
  60. # if true, #process returns nil
  61. 1 def hide_requested_view?
  62. 20902 optional? && hide?(requested_view)
  63. end
  64. # takes an options_hash and processes it to update viz_hash
  65. 1 def process_visibility_options options_hash
  66. 22282 %i[hide show].each do |setting|
  67. 44564 views = View.normalize_list(options_hash.delete(setting)).map(&:to_sym)
  68. 44564 viz views, setting, true
  69. end
  70. end
  71. 1 def normalized_visibility_options
  72. viz_hash.each_with_object({}) do |(key, val), hash|
  73. hash[val] ||= []
  74. hash[val] << key
  75. end
  76. end
  77. end
  78. end
  79. end
  80. end

card/lib/card/view/options/voo_api.rb

94.44% lines covered

90 relevant lines. 85 lines covered and 5 lines missed.
    
  1. 1 class Card
  2. 1 class View
  3. 1 module Options
  4. # VooApi methods let developers use view options dynamically.
  5. 1 module VooApi
  6. # There are two primary options hashes:
  7. # - @normalized_options are determined upon initialization and do not change
  8. # after that.
  9. # @return [Hash] options
  10. 1 attr_reader :normalized_options
  11. 1 class << self
  12. 1 def included base
  13. # Developers can also set most options directly via accessors,
  14. # eg voo.title = "King"
  15. # :view, :show, and :hide have non-standard access (see #accessible_keys)
  16. 1 base.accessible_keys.each do |option_key|
  17. 25 define_getter option_key unless option_key == :items
  18. 25 define_setter option_key
  19. end
  20. end
  21. 1 def define_getter option_key
  22. 25 define_method option_key do
  23. 47505 live_options[option_key]
  24. end
  25. end
  26. 1 def define_setter option_key
  27. 26 define_method "#{option_key}=" do |value|
  28. 128 live_options[option_key] = special_option_value(option_key, value) || value
  29. end
  30. end
  31. end
  32. # "items", the option used to configure views of each of a list of cards, is
  33. # currently the only Hash option (thus this accessor override)
  34. # @return [Hash]
  35. 1 def items
  36. 281 live_options[:items] ||= {}
  37. end
  38. # options to be used in data attributes of card slots (normalized options
  39. # with standard keys)
  40. # FIXME: what we really want is options as they were when render was called.
  41. # normalized is wrong because it can get changed before render. live is wrong
  42. # because they can get changed after. current solution is a compromise.
  43. # @return [Hash]
  44. 1 def slot_options
  45. 617 normalized_options.merge(view: requested_view).slice(*Options.slot_keys)
  46. end
  47. # ACCESSOR_HELPERS
  48. # methods that follow the normalize_#{key} pattern are called by accessors
  49. # (arguably that should be done during normalization!)
  50. 1 def normalize_special_options! opts
  51. 20915 opts.each do |option_key, value|
  52. 50474 new_value = special_option_value option_key, value
  53. 50474 opts[option_key] = new_value if new_value
  54. end
  55. end
  56. 1 def special_option_value option_key, value
  57. 50602 try "normalize_#{option_key}", value
  58. end
  59. 1 def normalize_input_type value
  60. 3 value&.to_sym
  61. end
  62. 1 def normalize_edit value
  63. 41 value&.to_sym
  64. end
  65. 1 def normalize_cache value
  66. 4 value&.to_sym
  67. end
  68. 1 def normalize_wrap value
  69. 44 value = value.split(",").map(&:strip) if value.is_a? String
  70. 44 Array.wrap(value).compact.flatten
  71. end
  72. 1 protected
  73. # - @live_options are dynamic and can be altered by the "voo" API at any time.
  74. # Such alterations are NOT used in the stub of the current voo, but they
  75. # ARE inherited by children voos.
  76. #
  77. # @return [Hash]
  78. 1 def live_options
  79. 315367 @live_options ||= process_live_options
  80. end
  81. 1 private
  82. # option normalization includes standardizing options into a hash with
  83. # symbols as keys, managing standard view inheritance, and special
  84. # handling for main_views.
  85. 1 def normalize_options
  86. 20912 @normalized_options = opts = options_to_hash @raw_options.clone
  87. 20912 normalize_special_options! opts
  88. 20912 @optional = opts.delete(:optional) || false
  89. 20912 add_implicit_options!
  90. 20912 inherit_options_from_parent!
  91. 20912 validate_options! opts
  92. 20912 opts
  93. end
  94. 1 def add_implicit_options!
  95. 20912 @normalized_options[:view] = @raw_view
  96. 20912 @normalized_options[:main] = true if format.main?
  97. # opts[:context_names] = format.context_names
  98. end
  99. # typically options are already a hash. this also handles an array of
  100. # hashes and nil.
  101. 1 def options_to_hash opts
  102. 20912 case opts
  103. when ActionController::Parameters
  104. opts.to_unsafe_h.deep_symbolize_keys
  105. 20912 when Hash then opts.deep_symbolize_keys!
  106. when Array then opts[0].merge(opts[1]).deep_symbolize_keys!
  107. when nil then {}
  108. else raise Card::Error, "bad view options: #{opts}"
  109. end
  110. end
  111. # standard inheritance from parent view object
  112. 1 def inherit_options_from_parent!
  113. 20912 return unless parent
  114. 11802 Options.heir_keys.each do |option_key|
  115. 224238 inherit_from_parent! option_key
  116. end
  117. end
  118. 1 def inherit_from_parent! option_key
  119. 224238 return unless (parent_value = parent.live_options[option_key])
  120. 11972 @normalized_options[option_key] ||= parent_value
  121. end
  122. 1 def process_live_options
  123. 20902 @live_options = normalized_options.clone
  124. 20902 process_main_nest_options
  125. 20902 process_before_view
  126. 20902 process_visibility
  127. 20902 return :hide if hide_requested_view? # bail to avoid unnecessary processing
  128. 20185 process_view_wrappers
  129. 20183 @live_options
  130. end
  131. # This method triggers the "before" blocks which can alter the @live_options
  132. # hash both directly and indirectly (via the voo API)
  133. 1 def process_before_view
  134. 20902 format.before_view requested_view
  135. end
  136. # adds the wrappers assigned to ok_view in view definition
  137. 1 def process_view_wrappers
  138. 20185 view_wrappers = format.view_setting(:wrap, ok_view)
  139. 20183 return unless view_wrappers.present?
  140. 436 @live_options[:wrap] = Array.wrap(@live_options[:wrap])
  141. 436 if view_wrappers.is_a? ::Hash
  142. 239 view_wrappers.each_pair do |name, opts|
  143. 240 @live_options[:wrap] << [name, opts]
  144. end
  145. else
  146. 197 @live_options[:wrap] += Array.wrap(view_wrappers)
  147. end
  148. end
  149. # merge the options of the main nest into the @live_options
  150. # They are not processed in normalize_options so that
  151. # they're NOT locked in the stub.
  152. 1 def process_main_nest_options
  153. 20902 @live_options.merge! format.main_nest_options if @live_options[:main_view]
  154. end
  155. 1 def validate_options! opts
  156. 20912 return unless (foreign_opts = foreign_options_in opts)
  157. # TODO: this should raise a UserError if the options come directly from params
  158. # (eg, mycard?slot[badoption]=true should not be treated as a server error)
  159. raise Card::Error, "illegal view options: #{foreign_opts}"
  160. end
  161. # find non-standard option in Hash
  162. # @param opts [Hash] options hash
  163. # @return [Hash] options Hash
  164. 1 def foreign_options_in opts
  165. 76255 foreign_opts = opts.reject { |k, _v| Options.all_keys.include? k }
  166. 20912 foreign_opts.empty? ? nil : foreign_opts
  167. end
  168. end
  169. end
  170. end
  171. end

card/lib/card/view/permission.rb

100.0% lines covered

25 relevant lines. 25 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 class View
  3. # View permissions support view-specific permission handling
  4. #
  5. # Views can be configured in {Set::Format::AbstractFormat#view view definitions}
  6. # with the `perms` directive, eg
  7. #
  8. # # only render if user has permission to update card
  9. # view :myview, perms: :update do...
  10. 1 module Permission
  11. 1 def view_perms
  12. 44650 @view_perms = setting(:perms) || :read
  13. end
  14. 1 private
  15. 1 def altered_view
  16. 20183 return if skip_check?
  17. 13877 alter_unknown || denial
  18. end
  19. 1 def skip_check?
  20. 20183 normalized_options[:skip_perms] || view_perms == :none
  21. end
  22. 1 def setting setting_name, view=nil
  23. 58527 view ||= requested_view
  24. 58527 format.view_setting setting_name, view
  25. end
  26. # by default views can't handle unknown cards, but this can be overridden in
  27. # view definitions with the `unknown` directive
  28. 1 def alter_unknown
  29. 13877 setting = setting(:unknown)
  30. 13877 return if setting == true || card.known?
  31. 73 setting.is_a?(Symbol) ? setting : format.view_for_unknown(requested_view)
  32. end
  33. 1 def denial
  34. 13804 return unless (task = denied_task)
  35. 111 format.view_for_denial requested_view, task
  36. end
  37. 1 def denied_task
  38. 13804 if view_perms.is_a? Proc
  39. 123 :read unless view_perms.call(format) # read isn't quite right
  40. else
  41. 27362 Array.wrap(view_perms).find { |task| !format.ok? task }
  42. end
  43. end
  44. end
  45. end
  46. end

card/mod/core/chunk/escaped_literal.rb

100.0% lines covered

10 relevant lines. 10 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 class Card
  3. 1 class Content
  4. 1 module Chunk
  5. # These are basic chunks that have a pattern and can be protected.
  6. # They are used by rendering process to prevent wiki rendering
  7. # occuring within literal areas such as <code> and <pre> blocks
  8. # and within HTML tags.
  9. 1 class EscapedLiteral < Abstract
  10. 1 FULL_RE = { "[" => /\A\\\[\[[^\]]*\]\]/,
  11. "{" => /\A\\\{\{[^\}]*\}\}/ }.freeze
  12. 1 Card::Content::Chunk.register_class self,
  13. prefix_re: '\\\\(?:\\[\\[|\\{\\{)',
  14. idx_char: '\\'
  15. 1 def self.full_re prefix
  16. 5 FULL_RE[prefix[1, 1]]
  17. end
  18. 1 def interpret match, _content
  19. 5 @process_chunk = match[0].sub(/^\\(.)/, format.escape_literal('\1'))
  20. end
  21. end
  22. end
  23. end
  24. end

card/mod/core/chunk/keep_escaped_literal.rb

100.0% lines covered

10 relevant lines. 10 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 class Card
  3. 1 class Content
  4. 1 module Chunk
  5. # These are basic chunks that have a pattern and can be protected.
  6. # This chunk is used for markdown processing to ensure that
  7. # the escaping survives the markdown rendering.
  8. 1 class KeepEscapedLiteral < Abstract
  9. 1 FULL_RE = { "[" => /\A\\\[\[[^\]]*\]\]/,
  10. "{" => /\A\\\{\{[^\}]*\}\}/ }.freeze
  11. 1 Card::Content::Chunk.register_class self,
  12. prefix_re: '\\\\(?:\\[\\[|\\{\\{)',
  13. idx_char: '\\'
  14. 1 def self.full_re prefix
  15. 2 FULL_RE[prefix[1, 1]]
  16. end
  17. 1 def interpret match, _content
  18. 2 @process_chunk = match[0].sub(/^\\(.)/, '\\\\\\\\\1')
  19. end
  20. end
  21. end
  22. end
  23. end

card/mod/core/chunk/link.rb

95.16% lines covered

62 relevant lines. 59 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. # require File.expand_path("../reference", __FILE__)
  3. 1 load File.expand_path("../reference.rb", __FILE__)
  4. 1 class Card
  5. 1 class Content
  6. 1 module Chunk
  7. # extend ActiveSupport::Autoload
  8. # autoload :Reference , "reference"
  9. 1 class Link < Card::Content::Chunk::Reference
  10. 1 CODE = "L".freeze # L for "Link"
  11. 1 attr_reader :link_text
  12. # Groups: $1, [$2]: [[$1]] or [[$1|$2]] or $3, $4: [$3][$4]
  13. 1 Card::Content::Chunk.register_class self,
  14. prefix_re: '\\[\\[',
  15. full_re: /\A\[\[([^\]]+)\]\]/,
  16. idx_char: "["
  17. 1 def reference_code
  18. 1714 CODE
  19. end
  20. 1 def interpret match, _content
  21. target, @link_text =
  22. 2606 if (raw_syntax = match[1])
  23. 2606 if (i = divider_index(raw_syntax)) # [[A | B]]
  24. 556 [raw_syntax[0..(i - 1)], raw_syntax[(i + 1)..-1]]
  25. else # [[ A ]]
  26. 2050 [raw_syntax, nil]
  27. end
  28. end
  29. 2606 @link_text = objectify @link_text
  30. 2606 if target.match? %r{^(/|https?:|mailto:)}
  31. 673 @explicit_link = objectify target
  32. else
  33. 1933 @name = target
  34. end
  35. end
  36. 1 def divider_index string
  37. # there's probably a better way to do the following.
  38. # point is to find the first pipe that's not inside an nest
  39. 2606 return unless string.index "|"
  40. 556 string_copy = string.dup
  41. 556 string.scan(/\{\{[^\}]*\}\}/) do |incl|
  42. 7 string_copy.gsub! incl, ("x" * incl.length)
  43. end
  44. 556 string_copy.index "|"
  45. end
  46. # view options
  47. 1 def options
  48. 379 link_text ? { title: link_text } : {}
  49. end
  50. 1 def objectify raw
  51. 3279 return unless raw
  52. 1229 raw.strip!
  53. 1229 if raw =~ /(^|[^\\])\{\{/
  54. 7 Card::Content.new raw, format
  55. else
  56. 1222 raw
  57. end
  58. end
  59. 1 def render_link view: :link, explicit_link_opts: {}
  60. 733 @link_text = render_obj @link_text
  61. 733 if @explicit_link
  62. 373 @explicit_link = render_obj @explicit_link
  63. 373 format.link_to_resource @explicit_link, @link_text, explicit_link_opts
  64. 360 elsif @name
  65. 360 format.with_nest_mode :normal do
  66. 360 format.nest referee_name, options.merge(view: view)
  67. end
  68. end
  69. end
  70. 1 def link_target
  71. 2 if @explicit_link
  72. 2 render_obj @explicit_link
  73. elsif @name
  74. referee_name
  75. end
  76. end
  77. 1 def process_chunk
  78. 489 @process_chunk ||= render_link
  79. end
  80. 1 def inspect
  81. "<##{self.class}:e[#{@explicit_link}]n[#{@name}]l[#{@link_text}]" \
  82. "p[#{@process_chunk}] txt:#{@text}>"
  83. end
  84. 1 def replace_reference old_name, new_name
  85. 88 replace_name_reference old_name, new_name
  86. 88 replace_link_text old_name, new_name
  87. @text =
  88. 88 @link_text.nil? ? "[[#{referee_name}]]" : "[[#{referee_name}|#{@link_text}]]"
  89. end
  90. 1 def replace_link_text old_name, new_name
  91. 88 if @link_text.is_a?(Card::Content)
  92. 1 @link_text.find_chunks(Card::Content::Chunk::Reference).each do |chunk|
  93. 1 chunk.replace_reference old_name, new_name
  94. end
  95. 87 elsif @link_text.present?
  96. 1 @link_text = old_name.to_name.sub_in(@link_text, with: new_name)
  97. end
  98. end
  99. 1 def explicit_link?
  100. 244 @explicit_link
  101. end
  102. end
  103. end
  104. end
  105. end

card/mod/core/chunk/nest.rb

92.42% lines covered

66 relevant lines. 61 lines covered and 5 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. # require File.expand_path("../reference", __FILE__)
  3. 1 class Card
  4. 1 class Content
  5. 1 module Chunk
  6. # Handler for nest chunks: {{example}}
  7. 1 class Nest < Reference
  8. 1 attr_reader :options
  9. 1 DEFAULT_OPTION = :view # a value without a key is interpreted as view
  10. 1 Chunk.register_class(self, prefix_re: '\\{\\{',
  11. full_re: /\A\{\{([^\{\}]*)\}\}/,
  12. idx_char: "{")
  13. 1 def interpret match, _content
  14. 3187 in_brackets = strip_tags match[1]
  15. 3187 name, @opt_lists = in_brackets.split "|", 2
  16. 3187 name = name.to_s.strip
  17. 3187 if name =~ /^\#/
  18. 4 @process_chunk = name =~ /^\#\#/ ? "" : visible_comment(in_brackets)
  19. else
  20. 3183 @options = interpret_options.merge nest_name: name,
  21. nest_syntax: in_brackets
  22. 3183 @name = name
  23. end
  24. end
  25. 1 def strip_tags string
  26. # note: not using ActionView's strip_tags here
  27. # because this needs to be super fast.
  28. 3187 string.gsub(/\<[^\>]*\>/, "")
  29. end
  30. 1 def visible_comment message
  31. 2 "<!-- #{CGI.escapeHTML message} -->"
  32. end
  33. 1 def interpret_options
  34. 3183 raw_options = @opt_lists.to_s.split("|").reverse
  35. 3183 raw_options.inject(nil) do |prev_level, level_options|
  36. 2857 interpret_piped_options level_options, prev_level
  37. end || {}
  38. end
  39. 1 def interpret_piped_options list_string, items
  40. 2857 options_hash = items.nil? ? {} : { items: items }
  41. 2857 option_string_to_hash list_string, options_hash
  42. 2857 options_hash
  43. end
  44. 1 def option_string_to_hash list_string, options_hash
  45. 2857 each_option(list_string) do |key, value|
  46. 2944 key = key.to_sym
  47. 2944 if key == :item
  48. 3 options_hash[:items] ||= {}
  49. 3 options_hash[:items][:view] = value
  50. 2941 elsif Card::View::Options.shark_keys.include? key
  51. 2929 options_hash[key] = value
  52. # else
  53. # handle other keys
  54. end
  55. end
  56. end
  57. 1 def inspect
  58. "<##{self.class}:n[#{@name}] p[#{@process_chunk}] txt:#{@text}>"
  59. end
  60. 1 def process_chunk
  61. 1908 return @process_chunk if @process_chunk
  62. 1905 referee_name
  63. 1905 @processed = format.content_nest(@options)
  64. # this is not necessarily text, sometimes objects for json
  65. end
  66. 1 def replace_reference old_name, new_name
  67. 89 replace_name_reference old_name, new_name
  68. 89 nest_body = [@name.to_s, @opt_lists].compact * "|"
  69. 89 @text = "{{#{nest_body}}}"
  70. end
  71. 1 def explicit_view= view
  72. return if @options[:view]
  73. # could check to make sure it's not already the default...
  74. if @text =~ /\|/
  75. @text.sub! "|", "|#{view};"
  76. else
  77. @text.sub! "}}", "|#{view}}}"
  78. end
  79. end
  80. 1 def main?
  81. 17 nest_name == "_main"
  82. end
  83. 1 def nest_name
  84. 17 options&.dig :nest_name
  85. end
  86. 1 def self.gsub string
  87. 22 string.gsub(/\{\{([^\}]*)\}\}/) do |_match|
  88. 21 yield(Regexp.last_match[1])
  89. end
  90. end
  91. 1 def raw_options
  92. 6 @opt_lists
  93. end
  94. 1 private
  95. 1 def each_option attr_string
  96. 2861 return if attr_string.blank?
  97. 2858 attr_string.strip.split(";").each do |pair|
  98. # key is optional for view option
  99. 2948 value, key = pair.split(":", 2).reverse
  100. 2948 key ||= self.class::DEFAULT_OPTION.to_s
  101. 2948 yield key.strip, value.strip
  102. end
  103. end
  104. end
  105. end
  106. end
  107. end

card/mod/core/chunk/query_reference.rb

96.3% lines covered

27 relevant lines. 26 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 class Card
  3. 1 class Content
  4. 1 module Chunk
  5. # This should find +Alfred+ in expressions like
  6. # 1) {"name":"Alfred"}
  7. # 2a) {"name":["in","Alfred"]}
  8. # 3a) {"plus_right":["Alfred"]}
  9. # but not in
  10. # 2b) "content":"foo", "Alfred":"bar"
  11. # 3b) {"name":["Alfred", "Toni"]} ("Alfred" is an operator here)
  12. # It's not possible to distinguish between 2a) and 2b) or 3a) and 3b) with a
  13. # simple regex, hence we use a too general regex and check for query keywords
  14. # after the match, which of course means that we don't find references with
  15. # query keywords as name
  16. 1 require File.expand_path("reference", __dir__)
  17. 1 class QueryReference < Reference
  18. 1 QUERY_KEYWORDS = ::Set.new(
  19. (
  20. 1 ::Card::Query::MODIFIERS.keys +
  21. ::Card::Query::OPERATORS.keys +
  22. ::Card::Query::ATTRIBUTES.keys +
  23. ::Card::Query::CONJUNCTIONS.keys +
  24. %w[desc asc count]
  25. ).map(&:to_s)
  26. )
  27. 1 Card::Content::Chunk.register_class(
  28. self, prefix_re: '(?<=[:,\\[])\\s*"',
  29. # we check for colon, comma or square bracket before a quote
  30. # we have to use a lookbehind, otherwise
  31. # if the colon matches it would be
  32. # identified mistakenly as an URI chunk
  33. full_re: /\A\s*"([^"]+)"/,
  34. idx_char: '"'
  35. )
  36. # OPTIMIZE: instead of comma or square bracket check for operator followed
  37. # by comma or "plus_right"|"plus_left"|"plus" followed by square bracket
  38. # something like
  39. # prefix_patterns = [
  40. # "\"\\s*(?:#{Card::Query::OPERATORS.keys.join('|')})\"\\s*,",
  41. # "\"\\s*(?:#{Card::Query::PLUS_ATTRIBUTES}.keys
  42. # .join('|')})\\s*:\\s*\\[\\s*",
  43. # "\"\\s*(?:#{(QUERY_KEYWORDS - Card::Query::PLUS_ATTRIBUTES)
  44. # .join('|')})\"\\s*:",
  45. # ]
  46. # prefix_re: '(?<=#{prefix_patterns.join('|')})\\s*"'
  47. # But: What do we do with the "in" operator? After the first value there is
  48. # no prefix which we can use to detect the following values as
  49. # QueryReference chunks
  50. 1 class << self
  51. 1 def full_match content, prefix
  52. # matches cardnames that are not keywords
  53. # FIXME: would not match cardnames that are keywords
  54. 338 match, offset = super(content, prefix)
  55. 338 return if !match || keyword?(match[1])
  56. 313 [match, offset]
  57. end
  58. 1 def keyword? str
  59. 338 return unless str
  60. 338 QUERY_KEYWORDS.include?(str.tr(" ", "_").downcase)
  61. end
  62. end
  63. 1 def interpret match, _content
  64. 313 @name = match[1]
  65. end
  66. 1 def process_chunk
  67. 4 @process_chunk ||= @text
  68. end
  69. 1 def inspect
  70. "<##{self.class}:n[#{@name}] p[#{@process_chunk}] txt:#{@text}>"
  71. end
  72. 1 def replace_reference old_name, new_name
  73. 2 replace_name_reference old_name, new_name
  74. 2 @text = "\"#{@name}\""
  75. end
  76. 1 def reference_code
  77. 293 "Q" # for "Query"
  78. end
  79. end
  80. end
  81. end
  82. end

card/mod/core/chunk/reference.rb

90.0% lines covered

30 relevant lines. 27 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 class Card
  3. 1 class Content
  4. 1 module Chunk
  5. 1 class Reference < Abstract
  6. 1 attr_accessor :referee_name, :name
  7. 1 def referee_name
  8. 5826 return if name.nil?
  9. 5532 @referee_name ||= referee_name_from_rendered(render_obj(name))
  10. 5532 @referee_name = @referee_name.absolute(card.name).to_name
  11. rescue Card::Error::NotFound
  12. # do not break on missing id/codename references.
  13. end
  14. 1 def referee_name_from_rendered rendered_name
  15. 5408 ref_card = fetch_referee_card rendered_name
  16. 5408 ref_card ? ref_card.name : rendered_name.to_name
  17. end
  18. 1 def referee_card
  19. 11 @referee_card ||= referee_name && Card.fetch(referee_name)
  20. end
  21. 1 def replace_name_reference old_name, new_name
  22. 179 @referee_card = nil
  23. 179 @referee_name = nil
  24. 179 if name.is_a? Card::Content
  25. name.find_chunks(Chunk::Reference).each do |chunk|
  26. chunk.replace_reference old_name, new_name
  27. end
  28. else
  29. 179 @name = name.to_name.swap old_name, new_name
  30. end
  31. end
  32. 1 def render_obj raw
  33. 6516 if format && raw.is_a?(Card::Content)
  34. 2 format.process_content raw
  35. else
  36. 6514 raw
  37. end
  38. end
  39. 1 private
  40. 1 def fetch_referee_card rendered_name
  41. 5408 case rendered_name # FIXME: this should be standard fetch option.
  42. when /^\~(\d+)$/ # get by id
  43. Card.fetch Regexp.last_match(1).to_i
  44. when /^\:(\w+)$/ # get by codename
  45. 143 Card.fetch Regexp.last_match(1).to_sym
  46. end
  47. end
  48. end
  49. end
  50. end
  51. end

card/mod/core/chunk/uri.rb

98.11% lines covered

53 relevant lines. 52 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 1 require "uri"
  3. # This wiki chunk matches arbitrary URIs, using patterns from the Ruby URI
  4. # modules.
  5. # It parses out a variety of fields that could be used by formats to format
  6. # the links in various ways (shortening domain names, hiding email addresses)
  7. # It matches email addresses and host.com.au domains without schemes (http://)
  8. # but adds these on as required.
  9. #
  10. # The heuristic used to match a URI is designed to err on the side of caution.
  11. # That is, it is more likely to not autolink a URI than it is to accidently
  12. # autolink something that is not a URI. The reason behind this is it is easier
  13. # to force a URI link by prefixing 'http://' to it than it is to escape and
  14. # incorrectly marked up non-URI.
  15. #
  16. # I'm using a part of the [ISO 3166-1 Standard][iso3166] for country name
  17. # suffixes.
  18. # The generic names are from www.bnoack.com/data/countrycode2.html)
  19. # [iso3166]: http://geotags.com/iso3166/
  20. 1 module Card::Content::Chunk
  21. 1 class URI < Abstract
  22. 1 SCHEMES = %w[irc http https ftp ssh git sftp file ldap ldaps mailto].freeze
  23. 6 REJECTED_PREFIX_RE = %w{! ": " ' ](}.map { |s| Regexp.escape s } * "|"
  24. 1 attr_reader :uri, :link_text
  25. 1 delegate :to, :scheme, :host, :port, :path, :query, :fragment, to: :uri
  26. 1 Card::Content::Chunk.register_class(
  27. self, prefix_re: "(?:(?!#{REJECTED_PREFIX_RE})(?:#{SCHEMES * '|'})\\:)",
  28. full_re: /\A#{::URI.regexp(SCHEMES)}/,
  29. idx_char: ":"
  30. )
  31. 1 class << self
  32. 1 def full_match content, prefix
  33. 213 prepend_str = if prefix[-1, 1] != ":" && config[:prepend_str]
  34. 140 config[:prepend_str]
  35. else
  36. 73 ""
  37. end
  38. 213 content = prepend_str + content
  39. 213 match = super content, prefix
  40. 213 [match, prepend_str.length]
  41. end
  42. 1 def context_ok? content, chunk_start
  43. 213 preceding_string = content[chunk_start - 2..chunk_start - 1]
  44. 213 preceding_string !~ /(?:#{REJECTED_PREFIX_RE})$/
  45. end
  46. end
  47. 1 def interpret match, _content
  48. 207 chunk = match[0]
  49. 207 last_char = chunk[-1, 1]
  50. 207 chunk.gsub!(/(?:&nbsp;)+/, "")
  51. @trailing_punctuation =
  52. 207 if %w[, . ) ! ? :].member?(last_char)
  53. 6 @text.chop!
  54. 6 chunk.chop!
  55. 6 last_char
  56. end
  57. 207 chunk.sub!(/\.$/, "")
  58. 207 @link_text = chunk
  59. 207 @uri = ::URI.parse(chunk)
  60. 207 @process_chunk = process_uri_chunk
  61. rescue ::URI::Error => e
  62. # warn "rescue parse #{chunk_class}:
  63. # '#{m}' #{e.inspect} #{e.backtrace*"\n"}"
  64. Rails.logger.warn "rescue parse #{self.class}: #{e.inspect}"
  65. end
  66. 1 private
  67. 1 def process_text
  68. 67 @link_text
  69. end
  70. 1 def process_uri_chunk
  71. 207 link = format.link_to_resource @link_text, process_text
  72. 207 "#{link}#{@trailing_punctuation}"
  73. end
  74. end
  75. # FIXME: DRY, merge these two into one class
  76. 1 class EmailURI < URI
  77. 1 PREPEND_STR = "mailto:".freeze
  78. 1 EMAIL = '[a-zA-Z\\d](?:[-a-zA-Z\\d.]*[a-zA-Z\\d])?\\@'.freeze
  79. 1 Card::Content::Chunk.register_class(
  80. self, prefix_re: "(?:(?!#{REJECTED_PREFIX_RE})#{EMAIL})\\b",
  81. full_re: /\A#{::URI.regexp(SCHEMES)}/,
  82. prepend_str: PREPEND_STR,
  83. idx_char: "@"
  84. )
  85. # removes the prepended string from the unchanged match text
  86. 1 def process_text
  87. 44 @text = @text.sub(/^mailto:/, "")
  88. end
  89. end
  90. 1 class HostURI < URI
  91. GENERIC = "aero|biz|com|coop|edu|gov|info|int|mil|" \
  92. 1 "museum|name|net|org".freeze
  93. COUNTRY = "ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|az|ba|bb|bd|be|" \
  94. "bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cf|cd|cg|" \
  95. "ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|" \
  96. "ec|ee|eg|eh|er|es|et|fi|fj|fk|fm|fo|fr|fx|ga|gb|gd|ge|gf|gh|" \
  97. "gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|" \
  98. "il|in|io|iq|ir|is|it|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|" \
  99. "kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|mg|mh|mk|ml|mm|" \
  100. "mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|" \
  101. "no|np|nr|nt|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|pt|pw|py|" \
  102. "qa|re|ro|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|" \
  103. "st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tm|tn|to|tp|tr|tt|tv|tw|" \
  104. "tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|" \
  105. "za|zm|zr|zw|" \
  106. 1 "eu".freeze # made this separate, since it's not technically
  107. # a country -efm
  108. # These are needed otherwise HOST will match almost anything
  109. 1 TLDS = "(?:#{GENERIC}|#{COUNTRY})".freeze
  110. # TLDS = "(?:#{GENERIC})"
  111. 1 PREPEND_STR = "http://".freeze
  112. 1 HOST = "(?:[a-zA-Z\\d](?:[-a-zA-Z\\d]*[a-zA-Z\\d])?\\.)+#{TLDS}".freeze
  113. 1 Card::Content::Chunk.register_class(
  114. self, prefix_re: "(?:(?!#{REJECTED_PREFIX_RE})#{HOST})\\b",
  115. full_re: /\A#{::URI.regexp(SCHEMES)}/,
  116. prepend_str: PREPEND_STR
  117. )
  118. # removes the prepended string from the unchanged match text
  119. 1 def process_text
  120. 96 @text = @text.sub(%r{^http://}, "")
  121. end
  122. end
  123. end

card/mod/core/chunk/view_stub.rb

48.39% lines covered

31 relevant lines. 15 lines covered and 16 lines missed.
    
  1. 1 class Card
  2. 1 class Content
  3. 1 module Chunk
  4. 1 class ViewStub < Abstract
  5. 1 Chunk.register_class(
  6. self,
  7. prefix_re: Regexp.escape("(StUb"),
  8. full_re: /\A\(StUb(.*?)sTuB\)/m,
  9. idx_char: "("
  10. )
  11. 1 def initialize text, content
  12. super
  13. end
  14. 1 def interpret match, _content
  15. @stub_hash = initial_stub_hash match[1]
  16. interpret_hash_values
  17. end
  18. 1 def initial_stub_hash string
  19. JSON.parse(string).symbolize_keys
  20. # MessagePack.unpack(hex_to_bin(string)).symbolize_keys
  21. end
  22. 1 def hex_to_bin string
  23. string.scan(/../).map { |x| x.hex.chr }.join
  24. end
  25. 1 def interpret_hash_values
  26. @stub_hash.keys.each do |key|
  27. send "interpret_#{key}"
  28. end
  29. end
  30. 1 def interpret_cast
  31. @stub_hash[:cast].symbolize_keys!
  32. end
  33. 1 def interpret_view_opts
  34. @stub_hash[:view_opts].symbolize_keys!
  35. end
  36. 1 def interpret_format_opts
  37. hash = @stub_hash[:format_opts]
  38. hash.symbolize_keys!
  39. hash[:nest_mode] = hash[:nest_mode].to_sym
  40. hash[:override] = hash[:override] == "true"
  41. hash[:context_names].map!(&:to_name)
  42. end
  43. 1 def process_chunk
  44. @processed = format.stub_nest @stub_hash
  45. end
  46. 1 def result
  47. @processed
  48. end
  49. end
  50. end
  51. end
  52. end

card/mod/core/lib/card/rule/preference_cache.rb

100.0% lines covered

30 relevant lines. 30 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 module Rule
  3. 1 class PreferenceCache < Cache
  4. 1 self.sql = %(
  5. SELECT
  6. preferences.id AS rule_id,
  7. settings.id AS setting_id,
  8. sets.id AS set_id,
  9. sets.left_id AS anchor_id,
  10. sets.right_id AS set_tag_id,
  11. users.id AS user_id
  12. FROM cards preferences
  13. JOIN cards user_sets ON preferences.left_id = user_sets.id
  14. JOIN cards settings ON preferences.right_id = settings.id
  15. JOIN cards users ON user_sets.right_id = users.id
  16. JOIN cards sets ON user_sets.left_id = sets.id
  17. WHERE sets.type_id = #{SetID}
  18. AND settings.type_id = #{SettingID}
  19. AND (users.type_id = #{UserID} or users.codename = 'all')
  20. AND sets.trash is false
  21. AND settings.trash is false
  22. AND users.trash is false
  23. AND user_sets.trash is false
  24. AND preferences.trash is false;
  25. ).freeze
  26. 1 self.cache_key = "PREFERENCES".freeze
  27. 1 USER_ID_CACHE_KEY = "USER_IDS".freeze
  28. 1 class << self
  29. 1 def user_ids
  30. 600 Card.cache.read(USER_ID_CACHE_KEY) || (populate && user_ids)
  31. end
  32. 1 def populate
  33. 83 @rows = nil
  34. 83 super.tap do
  35. 83 populate_user_ids
  36. 83 @rows = nil
  37. end
  38. end
  39. 1 def populate_user_ids
  40. 83 Card.cache.write USER_ID_CACHE_KEY, user_id_hash
  41. end
  42. 1 def user_id_hash
  43. 83 rows.each_with_object({}) do |row, hash|
  44. 1270 key = lookup_key_without_user row
  45. 1270 hash[key] ||= []
  46. 1270 hash[key] << row["user_id"]
  47. end
  48. end
  49. 1 def clear
  50. 304 super
  51. 304 Card.cache.write USER_ID_CACHE_KEY, nil
  52. end
  53. 1 def rows
  54. 166 @rows ||= super
  55. end
  56. 1 alias :lookup_key_without_user :lookup_key
  57. 1 def lookup_key row
  58. 1270 return unless (base = lookup_key_without_user row)
  59. 1270 "#{base}+#{row['user_id']}"
  60. end
  61. end
  62. end
  63. end
  64. end

card/mod/core/lib/card/rule/read_rule_cache.rb

100.0% lines covered

11 relevant lines. 11 lines covered and 0 lines missed.
    
  1. 1 class Card
  2. 1 module Rule
  3. 1 class ReadRuleCache < Cache
  4. 1 self.sql = %(
  5. SELECT
  6. refs.referee_id AS party_id,
  7. read_rules.id AS read_rule_id
  8. FROM cards read_rules
  9. JOIN card_references refs ON refs.referer_id = read_rules.id
  10. JOIN cards sets ON read_rules.left_id = sets.id
  11. WHERE read_rules.right_id = #{ReadID}
  12. AND sets.type_id = #{SetID}
  13. AND read_rules.trash is false
  14. AND sets.trash is false;
  15. ).freeze
  16. 1 self.cache_key = "READRULES".freeze
  17. 1 class << self
  18. 1 def lookup_hash
  19. 58 rows.each_with_object({}) do |row, h|
  20. 1641 party_id = row["party_id"].to_i
  21. 1641 h[party_id] ||= []
  22. 1641 h[party_id] << row["read_rule_id"].to_i
  23. end
  24. end
  25. end
  26. end
  27. end
  28. end

card/mod/standard/lib/card/layout/card_layout.rb

95.65% lines covered

23 relevant lines. 22 lines covered and 1 lines missed.
    
  1. 1 class Card
  2. 1 class Layout
  3. # Layout based on a card's content
  4. 1 class CardLayout < Layout
  5. 1 def layout_card
  6. 46 @layout_card ||= Card.quick_fetch @layout
  7. end
  8. 1 def render
  9. 36 @format.process_content layout_card.content, chunk_list: :references
  10. end
  11. 1 def fetch_main_nest_opts
  12. 10 main_nest = find_main_nest_chunk
  13. # don't .& me !! (can be false)
  14. 10 (main_nest && main_nest.options) ||
  15. raise(Card::Error, "no main nest found in layout \"#{@layout}\"")
  16. end
  17. 1 MAIN_NESTING_LIMIT = 5
  18. 1 def find_main_nest_chunk card=layout_card, depth=0
  19. 11 content = Card::Content.new(card.content, @format, chunk_list: :nest_only)
  20. 11 return false unless content.each_chunk.count.positive?
  21. 11 main_chunk(content) || go_deeper(content, depth)
  22. end
  23. 1 def go_deeper content, depth
  24. 1 return false if depth > MAIN_NESTING_LIMIT
  25. 1 content.each_chunk do |chunk|
  26. 1 main_chunk = find_main_nest_chunk chunk.referee_card, depth + 1
  27. 1 return main_chunk if main_chunk
  28. end
  29. false
  30. end
  31. 1 def main_chunk content
  32. 11 content.each_chunk.find(&:main?)
  33. end
  34. end
  35. end
  36. end

card/mod/standard/lib/card/layout/code_layout.rb

80.0% lines covered

5 relevant lines. 4 lines covered and 1 lines missed.
    
  1. 1 class Card
  2. 1 class Layout
  3. 1 class CodeLayout < Layout
  4. 1 def render
  5. @format.send Card::Set::Format.layout_method_name(@layout)
  6. end
  7. end
  8. end
  9. end

card/mod/standard/lib/card/layout/unknown_layout.rb

70.0% lines covered

10 relevant lines. 7 lines covered and 3 lines missed.
    
  1. 1 class Card
  2. 1 class Layout
  3. 1 class UnknownLayout < Layout
  4. 1 SCOPE = "mod.core.format.html_format".freeze
  5. 1 def render
  6. @format.output [header, text]
  7. end
  8. 1 def header
  9. @format.content_tag(:h1, @format.tr(:unknown_layout, scope: SCOPE, name: @layout))
  10. end
  11. 1 def text
  12. @format.tr(:available_layouts, scope: SCOPE,
  13. available_layouts: self.class.built_in_layouts)
  14. end
  15. end
  16. end
  17. end

card/tmpsets/set/mod001-utility/abstract/bs_badge.rb

56.25% lines covered

16 relevant lines. 9 lines covered and 7 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (BsBadge)
  4. #
  5. 1 module BsBadge;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/utility/set/abstract/bs_badge.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def labeled_badge count, label, opts={}
  10. haml :labeled_badge, badge_haml_opts(count, label, opts)
  11. end
  12. 1 def tab_badge count, label, opts={}
  13. haml :tab_badge, badge_haml_opts(count, label, opts)
  14. end
  15. 1 def badge_haml_opts count, label, opts
  16. process_badge_opts count, opts
  17. { count: count, label: label, klass: opts[:klass], color: opts[:color],
  18. title: opts[:title] }
  19. end
  20. 1 def process_badge_opts count, opts
  21. if count.try(:zero?) && !opts[:zero_ok]
  22. opts[:klass] = [opts[:klass], "disabled-o"].compact.join " "
  23. end
  24. opts[:color] ||= "secondary"
  25. end
  26. end
  27. end;end;end;end;
  28. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/utility/set/abstract/bs_badge.rb ~~

card/tmpsets/set/mod001-utility/abstract/filterable.rb

53.85% lines covered

13 relevant lines. 7 lines covered and 6 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (Filterable)
  4. #
  5. 1 module Filterable;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/utility/set/abstract/filterable.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def filterable filter_hash={}, html_opts={}
  10. add_class html_opts, "_filterable _noFilterUrlUpdates"
  11. html_opts[:data] ||= {}
  12. html_opts[:data][:filter] = filter_hash
  13. wrap_with :div, yield, html_opts
  14. end
  15. 1 def filtering selector=nil
  16. selector ||= "._filter-widget:visible"
  17. wrap_with :div, yield, class: "_filtering", "data-filter-selector": selector
  18. end
  19. end
  20. end;end;end;end;
  21. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/utility/set/abstract/filterable.rb ~~

card/tmpsets/set/mod001-utility/abstract/filterable_bar.rb

63.64% lines covered

11 relevant lines. 7 lines covered and 4 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (FilterableBar)
  4. #
  5. 1 module FilterableBar;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/utility/set/abstract/filterable_bar.rb"; end
  8. 1 include_set Abstract::Filterable
  9. 1 before :bar do
  10. class_up "bar-body", "_filterable"
  11. super()
  12. end
  13. 1 before :expanded_bar do
  14. class_up "bar", "_filterable"
  15. super()
  16. end
  17. end;end;end;end;
  18. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/utility/set/abstract/filterable_bar.rb ~~

card/tmpsets/set/mod001-utility/abstract/utility.rb

60.0% lines covered

10 relevant lines. 6 lines covered and 4 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (Utility)
  4. #
  5. 1 module Utility;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/utility/set/abstract/utility.rb"; end
  8. 1 def fetch_params params
  9. Env.params.select { |key, val| val && params.include?(key) }
  10. .with_indifferent_access
  11. end
  12. 1 def param_to_i key, default
  13. if (value = Env.params[key])
  14. value.to_i
  15. else
  16. default
  17. end
  18. end
  19. end;end;end;end;
  20. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/utility/set/abstract/utility.rb ~~

card/tmpsets/set/mod002-admin/self/admin.rb

28.77% lines covered

73 relevant lines. 21 lines covered and 52 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Admin"
  4. #
  5. # collect arrays of the form
  6. 1 module Admin;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/admin/set/self/admin.rb"; end
  9. # [task symbol, { execute_policy: block, stats_policy: block }]
  10. 1 basket :tasks
  11. 1 def run_task_from_task_basket task
  12. task = task.to_sym
  13. task_data = tasks.find {|h| h[:name].to_sym == task.to_sym}
  14. if !irreversibles_tasks_allowed? && task_data[:irreversible]
  15. not_allowed task_data[:stats][:link_text]
  16. else
  17. task_data[:execute_policy].call if task_data
  18. end
  19. end
  20. 1 event :admin_tasks, :initialize, on: :update do
  21. return unless (task = Env.params[:task])
  22. raise Card::Error::PermissionDenied, self unless Auth.always_ok?
  23. case task.to_sym
  24. when :clear_cache then Card::Cache.reset_all
  25. when :repair_references then Card::Reference.repair_all
  26. when :repair_permissions then Card.repair_all_permissions
  27. when :clear_solid_cache then Card.clear_solid_cache
  28. when :clear_machine_cache then Card.reset_all_machines
  29. when :clear_script_cache then Card.reset_script_machine
  30. when :clear_history
  31. not_allowed "clear history" unless irreversibles_tasks_allowed?
  32. Card::Action.delete_old
  33. else
  34. run_task_from_task_basket task
  35. end
  36. abort :success
  37. end
  38. 1 def not_allowed task
  39. raise Card::Error::PermissionDenied,
  40. "The admin task '#{task}' is disabled for security reasons.<br>"\
  41. "You can enable it with the config option 'allow_irreversible_admin_tasks'"
  42. end
  43. 1 def irreversibles_tasks_allowed?
  44. Cardio.config.allow_irreversible_admin_tasks
  45. end
  46. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  47. 1 view :core, cache: :never do
  48. stats = card_stats
  49. stats += cache_stats
  50. stats += memory_stats
  51. card.tasks.each do |task|
  52. stats += Array.wrap task[:stats]
  53. end
  54. table_content = stats.map { |args| stat_row(args) }
  55. table table_content, header: %w[Stat Value Action]
  56. end
  57. 1 def card_stats
  58. [
  59. { title: "cards",
  60. count: Card.where(trash: false) },
  61. { title: "actions",
  62. count: Card::Action },
  63. # link_text: "clear history",
  64. # task: "clear_history" },
  65. { title: "references",
  66. count: Card::Reference }
  67. # link_text: "repair all",
  68. # task: "repair_references" }
  69. ]
  70. end
  71. 1 def cache_stats
  72. [
  73. { title: "solid cache",
  74. count: solid_cache_count, unit: " cards",
  75. link_text: "clear solid cache",
  76. task: "clear_solid_cache" },
  77. { title: "machine cache",
  78. count: machine_cache_count, unit: " cards",
  79. link_text: "clear machine cache",
  80. task: "clear_machine_cache" }
  81. ]
  82. # return stats unless Card.config.view_cache#
  83. # stats << { title: "view cache",
  84. # count: Card::View,
  85. # link_text: "clear view cache",
  86. # task: "clear_view_cache" }
  87. end
  88. 1 def memory_stats
  89. oldmem = session[:memory]
  90. session[:memory] = newmem = card.profile_memory
  91. stats = [
  92. { title: "memory now",
  93. count: newmem, unit: "M",
  94. link_text: "clear cache", task: "clear_cache" }
  95. ]
  96. return stats unless oldmem
  97. stats << { title: "memory prev", count: oldmem, unit: "M" }
  98. stats << { title: "memory diff", count: newmem - oldmem, unit: "M" }
  99. stats
  100. end
  101. 1 def stat_row args={}
  102. res = [(args[:title] || "")]
  103. res << "#{count(args[:count])}#{args[:unit]}"
  104. return res unless args[:task]
  105. res << link_to_card(:admin, (args[:link_text] || args[:task]),
  106. path: { action: :update, task: args[:task] })
  107. res
  108. end
  109. 1 def count counter
  110. counter = counter.call if counter.is_a?(Proc)
  111. counter.respond_to?(:count) ? counter.count : counter
  112. end
  113. 1 def solid_cache_count
  114. Card.search right: { codename: "solid_cache" }, return: "count"
  115. end
  116. 1 def machine_cache_count
  117. Card::Virtual.where(right_id: MachineCacheID).count
  118. end
  119. 1 def delete_sessions_link months
  120. link_to_card :admin, months, path: { action: :update, months: months,
  121. task: "delete_old_sessions" }
  122. end
  123. end
  124. 1 def current_memory_usage
  125. `ps -o rss= -p #{Process.pid}`.to_i
  126. end
  127. 1 def profile_memory &block
  128. before = current_memory_usage
  129. if block_given?
  130. instance_eval(&block)
  131. else
  132. before = 0
  133. end
  134. (current_memory_usage - before) / 1024.to_i
  135. end
  136. end;end;end;end;
  137. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/admin/set/self/admin.rb ~~

card/tmpsets/set/mod002-admin/self/admin_info.rb

52.0% lines covered

25 relevant lines. 13 lines covered and 12 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "AdminInfo"
  4. #
  5. 1 module AdminInfo;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/admin/set/self/admin_info.rb"; end
  8. 1 basket :warnings
  9. # For each warning in the basket (eg :my_warning), the core view
  10. # will run a test by appending a question mark (eg #my_warning?).
  11. # If it fails it will generate a message by appending message
  12. # (eg #my_warning_message).
  13. 1 add_to_basket :warnings, :no_email_delivery
  14. 1 def no_email_delivery?
  15. Card.config.action_mailer.perform_deliveries == false
  16. end
  17. 1 def clean_html?
  18. false
  19. end
  20. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  21. 1 view :core do
  22. warnings = card.warnings.map do |warning|
  23. card.send("#{warning}?") ? send("#{warning}_message") : nil
  24. end
  25. warnings.compact!
  26. warnings.empty? ? "" : warning_alert(warnings)
  27. end
  28. 1 def warning_alert warnings
  29. admin_warn = I18n.t(:admin_warn, scope: "mod.admin.set.self.admin_info")
  30. # 'ADMINISTRATOR WARNING'
  31. alert :warning, true do
  32. "<h5>#{admin_warn}</h5>" + list_tag(warnings)
  33. end
  34. end
  35. 1 def no_email_delivery_message
  36. # "Email delivery is turned off."
  37. # "Change settings in config/application.rb to send sign up notifications."
  38. I18n.t(:email_off,
  39. scope: "mod.admin.set.self.admin_info",
  40. path: "config/application.rb")
  41. end
  42. 1 def warning_list_with_auto_scope warnings
  43. # 'ADMINISTRATOR WARNING'
  44. admin_warn = tr(:admin_warn)
  45. "<h5>#{admin_warn}</h5>" + warnings.join("\n")
  46. end
  47. end
  48. end;end;end;end;
  49. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/admin/set/self/admin_info.rb ~~

card/tmpsets/set/mod002-admin/self/debugger.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Debugger"
  4. #
  5. 1 module Debugger;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/admin/set/self/debugger.rb"; end
  8. 1 def raw_help_text
  9. "show more useful error pages"
  10. end
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/admin/set/self/debugger.rb ~~

card/tmpsets/set/mod002-admin/self/trash.rb

48.0% lines covered

25 relevant lines. 12 lines covered and 13 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Trash"
  4. #
  5. 1 module Trash;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/admin/set/self/trash.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :core do
  10. rows = trashed_cards.map { |tc| trash_table_row(tc) }
  11. output [
  12. restored,
  13. (empty_trash_link if rows.present?),
  14. table(rows, header: ["card", "deleted", "by", ""])
  15. ]
  16. end
  17. 1 def trashed_cards
  18. Card.where(trash: true).order(updated_at: :desc)
  19. end
  20. 1 def trash_table_row card
  21. [
  22. card.name,
  23. "#{time_ago_in_words(card.updated_at)} ago",
  24. Card[card.updater_id].name,
  25. "#{history_link(card)} | #{restore_link(card)}"
  26. ]
  27. end
  28. 1 def restored
  29. return unless (res_id = Env.params[:restore]) &&
  30. (res_card = Card[res_id.to_i])
  31. alert :success, true do
  32. wrap_with(:h5, "restored") + subformat(res_card).render_bar
  33. end
  34. end
  35. 1 def empty_trash_link
  36. wrap_with(
  37. :p,
  38. button_link("empty trash",
  39. btn_type: :default,
  40. path: { mark: :admin, action: :update, task: :empty_trash,
  41. success: { id: "~#{card.id}" } },
  42. "data-confirm" => "Are you sure you want to delete "\
  43. "all cards in the trash?")
  44. )
  45. end
  46. 1 def history_link trashed_card
  47. link_to_card trashed_card, "history",
  48. path: { view: :history, look_in_trash: true }
  49. end
  50. 1 def restore_link trashed_card
  51. before_delete = trashed_card.actions[-2]
  52. link_to "restore", method: :post,
  53. rel: "nofollow",
  54. remote: true,
  55. class: "slotter",
  56. path: { id: trashed_card.id,
  57. view: :open,
  58. look_in_trash: true,
  59. action: :update,
  60. restore: trashed_card.id,
  61. action_ids: [before_delete],
  62. success: { id: "~#{card.id}" } }
  63. end
  64. end
  65. end;end;end;end;
  66. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/admin/set/self/trash.rb ~~

card/tmpsets/set/mod002-admin/self/version.rb

100.0% lines covered

8 relevant lines. 8 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Version"
  4. #
  5. # -*- encoding : utf-8 -*-
  6. 1 module Version;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/admin/set/self/version.rb"; end
  9. # require "card/version"
  10. 1 def ok_to_read
  11. 23 true
  12. end
  13. 1 def content
  14. 23 Card::Version.release
  15. end
  16. # view :core, :raw
  17. end;end;end;end;
  18. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/admin/set/self/version.rb ~~

card/tmpsets/set/mod003-core/abstract/code_file.rb

78.0% lines covered

50 relevant lines. 39 lines covered and 11 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (CodeFile)
  4. #
  5. 1 module CodeFile;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/abstract/code_file.rb"; end
  8. 1 def self.included host_class
  9. 34 host_class.mattr_accessor :file_content_mod_name
  10. 34 host_class.file_content_mod_name = Card::Set.mod_name(caller)
  11. end
  12. # FIXME: these should abstracted and configured on the types
  13. # (same codes for `rake card:create:codefile`)
  14. # @return [Array<String>, String] the name of file(s) to be loaded
  15. 1 def source_files
  16. 12 case type_id
  17. when CoffeeScriptID then "#{codename}.js.coffee"
  18. when JavaScriptID then "#{codename}.js"
  19. 6 when CssID then "#{codename}.css"
  20. 6 when ScssID then "#{codename}.scss"
  21. end
  22. end
  23. 1 def source_dir
  24. 14 case type_id
  25. when CoffeeScriptID, JavaScriptID then "lib/javascript"
  26. 14 when CssID, ScssID then "lib/stylesheets"
  27. else
  28. "lib"
  29. end
  30. end
  31. 1 def find_file filename
  32. 22 modname = file_content_mod_name
  33. 22 modname = $1 if modname =~ /^card-mod-(\w*)/
  34. 22 mod_path = Card::Mod.dirs.path modname
  35. 22 file_path = File.join(mod_path, source_dir, filename)
  36. 22 unless File.exist?(file_path)
  37. Rails.logger.info "couldn't locate file #{filename} at #{file_path}"
  38. return nil
  39. end
  40. 22 file_path
  41. end
  42. 1 def existing_source_paths
  43. 9 Array.wrap(source_files).map do |filename|
  44. 11 find_file(filename)
  45. end.compact
  46. end
  47. 1 def source_changed? since:
  48. 2 existing_source_paths.any? { |path| ::File.mtime(path) > since }
  49. end
  50. 1 def content
  51. 9 Array.wrap(source_files).map do |filename|
  52. 11 if (source_path = find_file filename)
  53. 11 Rails.logger.info "reading file: #{source_path}"
  54. 11 File.read source_path
  55. end
  56. end.compact.join "\n"
  57. end
  58. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  59. 1 view :input do
  60. "Content is stored in file and can't be edited."
  61. end
  62. 1 view :file_size do
  63. "#{card.name}: #{number_to_human_size card.content.bytesize}"
  64. end
  65. 1 def short_content
  66. fa_icon("exclamation-circle", class: "text-muted pr-2") +
  67. wrap_with(:span, "file", class: "text-muted")
  68. end
  69. 1 def standard_submit_button
  70. multi_card_editor? ? super : ""
  71. end
  72. end
  73. 1 def coffee_files files
  74. files.map { |f| "script_#{f}.js.coffee" }
  75. end
  76. 1 def scss_files files
  77. 4 files.map { |f| "style_#{f}.scss" }
  78. end
  79. end;end;end;end;
  80. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/abstract/code_file.rb ~~

card/tmpsets/set/mod003-core/abstract/haml_file.rb

58.82% lines covered

17 relevant lines. 10 lines covered and 7 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (HamlFile)
  4. #
  5. 1 module HamlFile;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/abstract/haml_file.rb"; end
  8. 1 def self.included host_class
  9. host_class.mattr_accessor :template_path
  10. host_class.extend Card::Set::Format::HamlPaths
  11. host_class.template_path = host_class.haml_template_path
  12. end
  13. 1 def content
  14. File.read template_path
  15. end
  16. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  17. 1 view :input do
  18. "Content is managed by code and cannot be edited"
  19. end
  20. 1 def haml_locals
  21. {}
  22. end
  23. 1 view :core do
  24. haml card.content, haml_locals
  25. end
  26. end
  27. end;end;end;end;
  28. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/abstract/haml_file.rb ~~

card/tmpsets/set/mod003-core/abstract/lock.rb

100.0% lines covered

19 relevant lines. 19 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (Lock)
  4. #
  5. 1 module Lock;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/abstract/lock.rb"; end
  8. 1 def lock
  9. 1 was_already_locked = locked?
  10. 1 return if was_already_locked
  11. 1 Auth.as_bot do
  12. 1 lock!
  13. 1 yield
  14. end
  15. ensure
  16. 1 unlock! unless was_already_locked
  17. end
  18. 1 def lock_cache_key
  19. 4 "UPDATE-LOCK:#{key}"
  20. end
  21. 1 def locked?
  22. 2 Card.cache.read lock_cache_key
  23. end
  24. 1 def lock!
  25. 1 Card.cache.write lock_cache_key, true
  26. end
  27. 1 def unlock!
  28. 1 Card.cache.write lock_cache_key, false
  29. end
  30. end;end;end;end;
  31. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/abstract/lock.rb ~~

card/tmpsets/set/mod003-core/abstract/vendor_code_file.rb

90.0% lines covered

10 relevant lines. 9 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (VendorCodeFile)
  4. #
  5. 1 module VendorCodeFile;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/abstract/vendor_code_file.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 def self.included host_class
  10. 1 host_class.mattr_accessor :file_content_mod_name
  11. 1 host_class.file_content_mod_name = Card::Set.mod_name(caller)
  12. end
  13. 1 def source_dir
  14. "vendor"
  15. end
  16. end;end;end;end;
  17. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/abstract/vendor_code_file.rb ~~

card/tmpsets/set/mod003-core/all/abort.rb

75.0% lines covered

44 relevant lines. 33 lines covered and 11 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Abort)
  4. #
  5. 1 module Abort;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/abort.rb"; end
  8. # The Card#abort method is for cleanly exiting an action without continuing
  9. # to process any further events.
  10. #
  11. # Three statuses are supported:
  12. #
  13. # failure: adds an error, returns false on save
  14. # success: no error, returns true on save
  15. # triumph: similar to success, but if called on a subcard
  16. # it causes the entire action to abort (not just the subcard)
  17. 1 def abort status, msg="action canceled"
  18. 1 director.abort
  19. 1 if status == :failure && errors.empty?
  20. errors.add :abort, msg
  21. 1 elsif status.is_a?(Hash) && status[:success]
  22. success << status[:success]
  23. status = :success
  24. end
  25. 1 raise Card::Error::Abort.new(status, msg)
  26. end
  27. 1 def aborting
  28. yield
  29. errors.any? ? abort(:failure) : abort(:success)
  30. end
  31. 1 def abortable
  32. 1944 yield
  33. rescue Card::Error::Abort => e
  34. 1 handle_abort_error e
  35. end
  36. 1 private
  37. 1 def handle_abort_error e
  38. 1 if e.status == :triumph
  39. @supercard ? raise(e) : true
  40. 1 elsif e.status == :success
  41. 1 abort_success
  42. end
  43. end
  44. 1 def abort_success
  45. 1 if @supercard
  46. @supercard.subcards.delete key
  47. @supercard.director.subdirectors.delete self
  48. expire :soft
  49. end
  50. 1 true
  51. end
  52. # this is an override of standard rails behavior that rescues abort
  53. # makes it so that :success abortions do not rollback
  54. 1 def with_transaction_returning_status
  55. 375 status = nil
  56. 375 self.class.transaction do
  57. 375 add_to_transaction
  58. 375 remember_transaction_record_state
  59. 750 status = abortable { yield }
  60. 359 raise ActiveRecord::Rollback unless status
  61. end
  62. 359 status
  63. end
  64. # FIXME: these two do not belong here!
  65. 1 public
  66. 1 event :notable_exception_raised do
  67. error = Card::Error.current
  68. Rails.logger.debug "#{error.message}\n#{error.backtrace * "\n "}"
  69. end
  70. 1 def success
  71. 100 Env.success(name)
  72. end
  73. end;end;end;end;
  74. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/abort.rb ~~

card/tmpsets/set/mod003-core/all/actify.rb

100.0% lines covered

43 relevant lines. 43 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Actify)
  4. #
  5. 1 module Actify;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/actify.rb"; end
  8. 1 def act options={}, &block
  9. 571 if act_card
  10. 386 add_to_act options, &block
  11. else
  12. 185 start_new_act &block
  13. end
  14. end
  15. 1 def act_card
  16. 1761 Card::Director.act_card
  17. end
  18. 1 def act_card?
  19. 617 self == act_card
  20. end
  21. 1 module ClassMethods
  22. 1 def create! opts
  23. 62 card = Card.new opts
  24. 62 card.save!
  25. 62 card
  26. end
  27. 1 def create opts
  28. 27 card = Card.new opts
  29. 27 card.save
  30. 27 card
  31. end
  32. end
  33. 1 def save! *args
  34. 289 as_subcard = args.first&.delete :as_subcard
  35. 578 act(as_subcard: as_subcard) { super }
  36. end
  37. 1 def save(*)
  38. 82 act { super }
  39. end
  40. 1 def valid?(*)
  41. 330 act(validating: true) { super }
  42. end
  43. 1 def update *args
  44. 24 act { super }
  45. end
  46. 1 def update! *args
  47. 66 act { super }
  48. end
  49. 1 alias_method :update_attributes, :update
  50. 1 alias_method :update_attributes!, :update!
  51. 1 private
  52. 1 def start_new_act
  53. 185 self.director = nil
  54. 185 Director.run_act(self) do
  55. 370 run_callbacks(:act) { yield }
  56. end
  57. end
  58. 1 def add_to_act options={}
  59. 386 director.appoint self unless @director
  60. 386 director.head = true unless options[:validating] || options[:as_subcard]
  61. 386 yield
  62. end
  63. end;end;end;end;
  64. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/actify.rb ~~

card/tmpsets/set/mod003-core/all/active_card.rb

100.0% lines covered

7 relevant lines. 7 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (ActiveCard)
  4. #
  5. 1 module ActiveCard;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/active_card.rb"; end
  8. # FIXME: -this needs a better home!
  9. 1 def format opts={}
  10. 71 opts = { format: opts.to_sym } if [Symbol, String].member? opts.class
  11. 71 Card::Format.new self, opts
  12. end
  13. end;end;end;end;
  14. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/active_card.rb ~~

card/tmpsets/set/mod003-core/all/assign_attributes.rb

98.73% lines covered

79 relevant lines. 78 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (AssignAttributes)
  4. #
  5. 1 module AssignAttributes;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/assign_attributes.rb"; end
  8. 1 def assign_attributes args={}
  9. 2966 args = prepare_assignment_args args
  10. 2966 assign_with_subcards args do
  11. 2966 assign_with_set_modules args do
  12. 2966 params = prepare_assignment_params args
  13. 2966 super params
  14. end
  15. end
  16. end
  17. 1 def assign_set_specific_attributes
  18. 4197 set_specific.each_pair do |name, value|
  19. 6 send "#{name}=", value
  20. end
  21. end
  22. 1 def extract_subcard_args! args
  23. 2966 subcards = args.delete("subcards") || args.delete(:subcards) || {}
  24. 2966 if (subfields = args.delete("subfields") || args.delete(:subfields))
  25. 3 subfields.each_pair do |key, value|
  26. 3 subcards[name.field(key)] = value
  27. end
  28. end
  29. 2966 args.keys.each do |key|
  30. 4292 subcards[key] = args.delete(key) if key =~ /^\+/
  31. end
  32. 2966 subcards = subcards.to_unsafe_h if subcards.respond_to?(:to_unsafe_h)
  33. 2966 subcards
  34. end
  35. 1 protected
  36. 1 module ClassMethods
  37. 1 def assign_or_newish name, attributes, fetch_opts={}
  38. 95 if (known_card = Card.fetch(name, fetch_opts))
  39. 11 known_card.refresh.newish attributes
  40. 11 known_card
  41. else
  42. 84 Card.new attributes.merge(name: name)
  43. end
  44. end
  45. end
  46. 1 def prepare_assignment_params args
  47. 2966 args = args.to_unsafe_h if args.respond_to?(:to_unsafe_h)
  48. 2966 params = ActionController::Parameters.new(args)
  49. 2966 params.permit!
  50. 2966 params[:db_content] = standardize_content(params[:db_content]) if params[:db_content]
  51. 2966 params
  52. end
  53. 1 def prepare_assignment_args args
  54. 2966 return {} unless args
  55. 2966 args = args.stringify_keys
  56. 2966 normalize_type_attributes args
  57. 2966 stash_set_specific_attributes args
  58. 2966 args
  59. end
  60. 1 def assign_with_set_modules args
  61. 2966 set_changed = args["name"] || args["type_id"]
  62. 2966 return yield unless set_changed
  63. 5842 refresh_set_modules { yield }
  64. end
  65. 1 def assign_with_subcards args
  66. 2966 subcard_args = extract_subcard_args! args
  67. 2966 yield
  68. # name= must come before process subcards
  69. 2966 return unless subcard_args.present?
  70. 27 subcards.add subcard_args
  71. end
  72. 1 def refresh_set_modules
  73. 2921 reinclude_set_modules = @set_mods_loaded
  74. 2921 yield
  75. 2921 reset_patterns
  76. 2921 include_set_modules if reinclude_set_modules
  77. end
  78. 1 def stash_set_specific_attributes args
  79. 2966 @set_specific = {}
  80. 2966 Card.set_specific_attributes.each do |key|
  81. 26694 set_specific[key] = args.delete(key) if args.key?(key)
  82. end
  83. end
  84. 1 def normalize_type_attributes args
  85. 2966 new_type_id = extract_type_id! args unless args.delete("type_lookup") == :skip
  86. 2966 args["type_id"] = new_type_id if new_type_id
  87. end
  88. 1 def extract_type_id! args={}
  89. case
  90. 1817 when (type_id = args.delete("type_id")&.to_i)
  91. 107 type_id.zero? ? nil : type_id
  92. 1710 when (type_code = args.delete("type_code")&.to_sym)
  93. 2 type_id_from_codename type_code
  94. 1708 when (type_name = args.delete "type")
  95. 1125 type_id_from_cardname type_name
  96. end
  97. end
  98. 1 def type_id_from_codename type_code
  99. 4 type_id_or_error(type_code) { Card::Codename.id type_code }
  100. end
  101. 1 def type_id_from_cardname type_name
  102. 2250 type_id_or_error(type_name) { Card.fetch_id type_name }
  103. end
  104. 1 def type_id_or_error val
  105. 1127 type_id = yield
  106. 1127 return type_id if type_id
  107. errors.add :type, "#{val} is not a known type."
  108. nil
  109. end
  110. # 'set' refers to the noun not the verb
  111. 1 def set_specific
  112. 4410 @set_specific ||= {}
  113. end
  114. end;end;end;end;
  115. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/assign_attributes.rb ~~

card/tmpsets/set/mod003-core/all/cache.rb

82.09% lines covered

67 relevant lines. 55 lines covered and 12 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Cache)
  4. #
  5. 1 module Cache;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/cache.rb"; end
  8. 1 module ClassMethods
  9. 1 def retrieve_from_cache cache_key, local_only=false
  10. 39857 return unless cache
  11. 39857 local_only ? cache.soft.read(cache_key) : cache.read(cache_key)
  12. end
  13. 1 def retrieve_from_cache_by_id id, local_only=false
  14. 13001 key = Card::Lexicon.name(id)&.key
  15. 13001 return unless key.present?
  16. 13000 retrieve_from_cache key, local_only if key
  17. end
  18. 1 def retrieve_from_cache_by_key key, local_only=false
  19. 26857 retrieve_from_cache key, local_only
  20. end
  21. 1 def write_to_cache card, local_only=false
  22. 6755 if local_only
  23. 52 write_to_soft_cache card
  24. 6703 elsif cache
  25. 6703 cache.write card.key, card
  26. end
  27. end
  28. 1 def write_to_soft_cache card
  29. 508 return unless cache
  30. 508 cache.soft.write card.key, card
  31. end
  32. 1 def expire name
  33. 24 key = name.to_name.key
  34. 24 return unless (card = Card.cache.read key)
  35. 6 card.expire
  36. end
  37. end
  38. 1 def update_soft_cache
  39. Card.write_to_soft_cache self
  40. end
  41. 1 def expire_pieces
  42. name.piece_names.each do |piece|
  43. Card.expire piece
  44. end
  45. end
  46. 1 def expire cache_type=nil
  47. 385 return unless (cache_class = cache_class_from_type cache_type)
  48. 359 expire_views
  49. 359 expire_names cache_class
  50. 359 expire_id cache_class
  51. end
  52. 1 def cache_class_from_type cache_type
  53. 385 cache_type ? Card.cache.send(cache_type) : Card.cache
  54. end
  55. 1 def view_cache_clean?
  56. !db_content_changed?
  57. end
  58. 1 def view_cache_keys
  59. 359 @view_cache_keys ||= hard_read_view_cache_keys || []
  60. end
  61. 1 def ensure_view_cache_key cache_key
  62. return if view_cache_keys.include? cache_key
  63. @view_cache_keys << cache_key
  64. hard_write_view_cache_keys
  65. end
  66. 1 def hard_read_view_cache_keys
  67. 334 Card.cache.hard&.read_attribute key, :view_cache_keys
  68. end
  69. 1 def hard_write_view_cache_keys
  70. # puts "WRITE VIEW CACHE KEYS (#{name}): #{view_cache_keys}"
  71. Card.cache.hard&.write_attribute key, :view_cache_keys, view_cache_keys
  72. end
  73. 1 def expire_views
  74. # puts "EXPIRE VIEW CACHE (#{name}): #{view_cache_keys}"
  75. 359 return unless view_cache_keys.present?
  76. Array.wrap(view_cache_keys).each do |view_cache_key|
  77. Card::View.cache.delete view_cache_key
  78. end
  79. @view_cache_keys = []
  80. hard_write_view_cache_keys
  81. end
  82. 1 def expire_names cache
  83. 359 [name, name_before_act].uniq.each do |name_version|
  84. 524 expire_name name_version, cache
  85. end
  86. end
  87. 1 def expire_name name_version, cache
  88. 524 return unless name_version.present?
  89. 422 key_version = name_version.to_name.key
  90. 422 return unless key_version.present?
  91. 422 cache.delete key_version
  92. end
  93. 1 def expire_id cache
  94. 359 return unless id.present?
  95. 349 cache.delete "~#{id}"
  96. end
  97. end;end;end;end;
  98. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/cache.rb ~~

card/tmpsets/set/mod003-core/all/chunk.rb

37.35% lines covered

83 relevant lines. 31 lines covered and 52 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Chunk)
  4. #
  5. 1 module Chunk;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/chunk.rb"; end
  8. 1 def chunks content, type, named=false
  9. content ||= self.content
  10. type ||= Card::Content::Chunk
  11. all_chunks = Card::Content.new(content, self).find_chunks type
  12. named ? all_chunks.select(&:referee_name) : all_chunks
  13. end
  14. 1 def reference_chunks content=nil, named=true
  15. chunks content, Card::Content::Chunk::Reference, named
  16. end
  17. # named=true rejects commented nests
  18. 1 def nest_chunks content=nil, named=true
  19. chunks content, Card::Content::Chunk::Nest, named
  20. end
  21. # named=true rejects external links (since the don't refer to a card name)
  22. 1 def link_chunks content=nil, named=false
  23. chunks content, Card::Content::Chunk::Link, named
  24. end
  25. 1 def each_item_name_with_options content=nil
  26. reference_chunks(content).each do |chunk|
  27. options = chunk.respond_to?(:options) ? chunk.options : {}
  28. yield chunk.referee_name, options
  29. end
  30. end
  31. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  32. 1 def nest_chunks content=nil
  33. content ||= _render_raw
  34. card.nest_chunks content
  35. end
  36. 1 def nested_cards content=nil
  37. nest_chunks(content).map(&:referee_card).uniq
  38. end
  39. 1 def edit_fields
  40. 20 voo.edit_structure || []
  41. end
  42. 1 def nested_field_names content=nil
  43. nest_chunks(content).map(&:referee_name).select { |n| field_name? n }
  44. end
  45. 1 def nested_field_cards content=nil
  46. nested_cards(content).select { |c| field_name? c.name }
  47. end
  48. 1 def field_name? name
  49. name.field_of? card.name
  50. end
  51. # @return [Array] of Arrays. each is [nest_name, nest_options_hash]
  52. 1 def edit_field_configs fields_only=false
  53. if edit_fields.present?
  54. explicit_edit_fields_config # explicitly configured in voo or code
  55. else
  56. implicit_edit_fields_config fields_only # inferred from nests
  57. end
  58. end
  59. 1 def implicit_edit_fields_config fields_only
  60. result = []
  61. each_nested_chunk(fields: fields_only) do |chunk|
  62. result << [chunk.options[:nest_name], chunk.options]
  63. end
  64. result
  65. end
  66. 1 def each_nested_field_chunk &block
  67. each_nested_chunk fields: true, &block
  68. end
  69. 1 def each_nested_chunk content: nil, fields: false, uniq: true, virtual: true, &block
  70. return unless block_given?
  71. chunks = prepare_nested_chunks content, fields, uniq
  72. process_nested_chunks chunks, virtual, &block
  73. end
  74. 1 def uniq_chunks chunks
  75. processed = ::Set.new [card.key]
  76. chunks.select do |chunk|
  77. key = chunk.referee_name.key
  78. ok = !processed.include?(key)
  79. processed << key
  80. ok
  81. end
  82. end
  83. 1 def field_chunks chunks
  84. chunks.select { |chunk| field_name?(chunk.referee_name) }
  85. end
  86. 1 private
  87. 1 def prepare_nested_chunks content, fields, uniq
  88. chunks = nest_chunks content
  89. chunks = field_chunks chunks if fields
  90. chunks = uniq_chunks chunks if uniq
  91. chunks
  92. end
  93. 1 def process_nested_chunks chunks, virtual, &block
  94. chunks.each do |chunk|
  95. process_nested_chunk chunk, virtual, &block
  96. end
  97. end
  98. 1 def process_nested_chunk chunk, virtual, &block
  99. if chunk.referee_card&.virtual?
  100. process_nested_virtual_chunk chunk, &block unless virtual
  101. else
  102. yield chunk
  103. end
  104. end
  105. 1 def process_virtual_chunk chunk
  106. subformat(chunk.referee_card).each_nested_field_chunk { |sub_chunk| yield sub_chunk }
  107. end
  108. 1 def explicit_edit_fields_config
  109. edit_fields.map do |cardish, options|
  110. field_mark = normalized_edit_field_mark cardish, options
  111. options = normalized_edit_field_options options, Card::Name[field_mark]
  112. [field_mark, options]
  113. end
  114. end
  115. 1 def normalized_edit_field_options options, cardname
  116. options ||= cardname
  117. options.is_a?(String) ? { title: options } : options
  118. end
  119. 1 def normalized_edit_field_mark cardish, options
  120. return cardish if cardish.is_a?(Card) ||
  121. (options.is_a?(Hash) && options.delete(:absolute))
  122. card.name.field cardish
  123. end
  124. end
  125. end;end;end;end;
  126. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/chunk.rb ~~

card/tmpsets/set/mod003-core/all/codename.rb

66.67% lines covered

21 relevant lines. 14 lines covered and 7 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Codename)
  4. #
  5. 1 module Codename;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/codename.rb"; end
  8. 1 def codename
  9. 811 super&.to_sym
  10. end
  11. 1 event :validate_codename, :validate, on: :update, changed: :codename do
  12. validate_codename_permission
  13. validate_codename_uniqueness
  14. end
  15. 1 event :reset_codename_cache, :integrate, changed: :codename do
  16. 265 return if action == :create && codename.nil?
  17. 76 Card::Codename.reset_cache
  18. 76 Card::Codename.generate_id_constants
  19. end
  20. 1 private
  21. 1 def validate_codename_permission
  22. return if Auth.always_ok? || Auth.as_id == creator_id
  23. errors.add :codename, tr(:only_admins_codename)
  24. end
  25. 1 def validate_codename_uniqueness
  26. return (self.codename = nil) if codename.blank?
  27. return if errors.present? || !Card.find_by_codename(codename)
  28. errors.add :codename, tr(:error_code_in_use, codename: codename)
  29. end
  30. end;end;end;end;
  31. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/codename.rb ~~

card/tmpsets/set/mod003-core/all/collection.rb

66.67% lines covered

33 relevant lines. 22 lines covered and 11 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Collection)
  4. #
  5. # shared methods for card collections (Pointers, Searches, Sets, etc.)
  6. 1 module Collection;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/collection.rb"; end
  9. 1 module ClassMethods
  10. 1 def search spec, comment=nil
  11. 461 results = ::Card::Query.run(spec, comment)
  12. 461 if block_given? && results.is_a?(Array)
  13. 8 results.each { |result| yield result }
  14. end
  15. 461 results
  16. end
  17. 1 def count_by_cql spec
  18. 7 spec = spec.clone
  19. 7 spec.delete(:offset)
  20. 7 search spec.merge(return: "count")
  21. end
  22. 1 def find_each options={}
  23. # this is a copy from rails (3.2.16) and is needed because this
  24. # is performed by a relation (ActiveRecord::Relation)
  25. find_in_batches(options) do |records|
  26. records.each { |record| yield record }
  27. end
  28. end
  29. 1 def find_in_batches options={}
  30. if block_given?
  31. super(options) do |records|
  32. yield(records)
  33. Card::Cache.reset_soft
  34. end
  35. else
  36. super(options)
  37. end
  38. end
  39. end
  40. 1 def collection?
  41. 26 item_cards != [self]
  42. end
  43. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  44. 1 view :count do
  45. card.item_names.size
  46. end
  47. end
  48. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  49. 1 view :carousel do
  50. bs_carousel unique_id, 0 do
  51. nest_item_array.each do |rendered_item|
  52. item(rendered_item)
  53. end
  54. end
  55. end
  56. end
  57. end;end;end;end;
  58. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/collection.rb ~~

card/tmpsets/set/mod003-core/all/content.rb

75.0% lines covered

92 relevant lines. 69 lines covered and 23 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Content)
  4. #
  5. 1 module Content;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/content.rb"; end
  8. 1 def content= value
  9. 57 self.db_content = standardize_content(value)
  10. end
  11. 1 def content
  12. 2609 structured_content || standard_content
  13. end
  14. 1 alias raw_content content #DEPRECATED!
  15. 1 def content?
  16. 2 content.present?
  17. end
  18. 1 def standard_content
  19. 2785 db_content || (new_card? && template.db_content)
  20. end
  21. 1 def standardize_content value
  22. 143 value.is_a?(Array) ? value.join("\n") : value
  23. end
  24. 1 def structured_content
  25. 2609 structure && template.db_content
  26. end
  27. 1 def refresh_content
  28. self.content = Card.find(id)&.db_content
  29. end
  30. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  31. 1 ONE_LINE_CHARACTER_LIMIT = 60
  32. 1 def chunk_list # override to customize by set
  33. 295 :default
  34. end
  35. 1 view :one_line_content do
  36. with_nest_mode :compact do
  37. one_line_content
  38. end
  39. end
  40. # DEPRECATED
  41. 1 view :closed_content, :one_line_content
  42. 1 view :raw_one_line_content do
  43. raw_one_line_content
  44. end
  45. 1 view :label do
  46. card.label.to_s
  47. end
  48. 1 view :smart_label, cache: :never, unknown: true do
  49. label_with_description render_label, label_description
  50. end
  51. 1 def label_with_description label, description
  52. return label unless description
  53. "#{label} #{popover_link description}"
  54. end
  55. # TODO: move this into a nest once popovers are stub safe
  56. 1 def label_description
  57. return unless (desc = card.field :description)
  58. desc.format.render_core
  59. end
  60. 1 def raw_one_line_content
  61. cut_with_ellipsis render_raw
  62. end
  63. 1 def one_line_content
  64. Card::Content.smart_truncate render_core
  65. end
  66. 1 def cut_with_ellipsis text, limit=one_line_character_limit
  67. if text.size <= limit
  68. text
  69. else
  70. text[0..(limit - 3)] + "..."
  71. end
  72. end
  73. 1 def one_line_character_limit
  74. voo.size || ONE_LINE_CHARACTER_LIMIT
  75. end
  76. end
  77. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  78. 1 view :hidden_content_field, unknown: true, cache: :never do
  79. 12 hidden_field :content, class: "d0-card-content"
  80. end
  81. end
  82. # seems like this should be moved to format so we can fall back on title
  83. # rather than name. (In fact, name, title, AND label is a bit much.
  84. # Trim to 2?)
  85. 1 def label
  86. name
  87. end
  88. 1 def creator
  89. Card[creator_id]
  90. end
  91. 1 def updater
  92. Card[updater_id]
  93. end
  94. 1 def save_content_draft _content
  95. clear_drafts
  96. end
  97. 1 def clear_drafts
  98. 242 drafts.created_by(Card::Auth.current_id).each(&:delete)
  99. end
  100. 1 def last_draft_content
  101. drafts.last.card_changes.last.value
  102. end
  103. 1 event :set_content, :store, on: :save do
  104. 242 self.db_content = prepare_db_content
  105. 242 @selected_action_id = @selected_content = nil
  106. 242 clear_drafts
  107. end
  108. 1 event :save_draft, :store, on: :update, when: :draft? do
  109. save_content_draft content
  110. abort :success
  111. end
  112. 1 event :set_default_content,
  113. :prepare_to_validate,
  114. on: :create, when: :use_default_content? do
  115. 15 self.db_content = template.db_content
  116. end
  117. 1 def draft?
  118. 53 Env.params["draft"] == "true"
  119. end
  120. 1 def prepare_db_content
  121. 242 cont = standard_db_content || "" # necessary?
  122. 242 clean_html? ? Card::Content.clean!(cont) : cont
  123. end
  124. 1 def standard_db_content
  125. 242 if structure
  126. # do not override db_content with content from structure
  127. 16 db_content
  128. else
  129. 226 standard_content
  130. end
  131. end
  132. 1 def clean_html?
  133. 242 true
  134. end
  135. 1 def use_default_content?
  136. 196 !db_content_changed? && template && template.db_content.present?
  137. end
  138. 1 def unfilled?
  139. 34 blank_content? && blank_comment? && !subcards?
  140. end
  141. 1 def blank_content?
  142. 34 content.blank? || content.strip.blank?
  143. end
  144. 1 def blank_comment?
  145. 2 comment.blank? || comment.strip.blank?
  146. end
  147. end;end;end;end;
  148. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/content.rb ~~

card/tmpsets/set/mod003-core/all/contextual_content.rb

100.0% lines covered

20 relevant lines. 20 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (ContextualContent)
  4. #
  5. 1 module ContextualContent;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/contextual_content.rb"; end
  8. 1 def context_card
  9. 2344 @context_card || self
  10. end
  11. 1 def with_context context_card
  12. 6 old_context = @context_card
  13. 6 @context_card = context_card if context_card
  14. 6 yield
  15. ensure
  16. 6 @context_card = old_context
  17. end
  18. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  19. 1 def context_card
  20. 541 card.context_card
  21. end
  22. 1 def with_context context_card
  23. 6 card.with_context context_card do
  24. 6 yield
  25. end
  26. end
  27. 1 def contextual_content context_card, options={}
  28. 6 view = options.delete(:view) || :core
  29. 12 with_context(context_card) { render! view, options }
  30. end
  31. end
  32. end;end;end;end;
  33. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/contextual_content.rb ~~

card/tmpsets/set/mod003-core/all/debug.rb

100.0% lines covered

19 relevant lines. 19 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Debug)
  4. #
  5. 1 module Debug;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/debug.rb"; end
  8. 1 def to_s
  9. 2 "#<#{self.class.name}[#{debug_type}]#{attributes['name']}>"
  10. end
  11. 1 def inspect
  12. 12 tags = []
  13. 12 tags << "trash" if trash
  14. 12 tags << "new" if new_card?
  15. 12 tags << "frozen" if frozen?
  16. 12 tags << "readonly" if readonly?
  17. 12 tags << "virtual" if @virtual
  18. 12 tags << "set_mods_loaded" if @set_mods_loaded
  19. 12 error_messages = errors.any? ? "<E*#{errors.full_messages * ', '}*>" : ""
  20. 12 "#<Card##{id}[#{debug_type}](#{name})#{error_messages}{#{tags * ','}}"
  21. end
  22. 1 private
  23. 1 def debug_type
  24. 14 "#{type_code || ''}:#{type_id}"
  25. end
  26. end;end;end;end;
  27. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/debug.rb ~~

card/tmpsets/set/mod003-core/all/event_conditions.rb

79.35% lines covered

92 relevant lines. 73 lines covered and 19 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (EventConditions)
  4. #
  5. 1 module EventConditions;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/event_conditions.rb"; end
  8. 1 Card.action_specific_attributes +=
  9. %i[skip_hash full_skip_hash trigger_hash full_trigger_hash]
  10. 1 def event_applies? event
  11. 56250 return unless set_condition_applies? event.set_module, event.opts[:changing]
  12. 17604 Card::Set::Event::CONDITIONS.all? do |key|
  13. 64349 send "#{key}_condition_applies?", event, event.opts[key]
  14. end
  15. end
  16. # force skipping this event for all cards in act
  17. 1 def skip_event! *events
  18. 11 @full_skip_hash = nil
  19. 11 events.each do |event|
  20. 22 act_skip_hash[event.to_s] = :force
  21. end
  22. end
  23. # force skipping this event for this card only
  24. 1 def skip_event_in_action! *events
  25. events.each do |event|
  26. full_skip_hash[event.to_s] = :force
  27. end
  28. end
  29. # force triggering this event (when it comes up) for all cards in act
  30. 1 def trigger_event! *events
  31. @full_trigger_hash = nil
  32. events.each do |event|
  33. act_trigger_hash[event.to_s] = :force
  34. end
  35. end
  36. # force triggering this event (when it comes up) for this card only
  37. 1 def trigger_event_in_action! *events
  38. events.each do |event|
  39. full_trigger_hash[event.to_s] = :force
  40. end
  41. end
  42. # hash form of raw skip setting, eg { "my_event" => true }
  43. 1 def skip_hash
  44. 387 @skip_hash ||= hash_with_value skip, true
  45. end
  46. 1 def trigger_hash
  47. @trigger_hash ||= hash_with_value trigger, true
  48. end
  49. 1 private
  50. 1 def set_condition_applies? set_module, old_sets
  51. 56250 return true if set_module == Card
  52. 56250 set_condition_card(old_sets).singleton_class.include? set_module
  53. end
  54. 1 def on_condition_applies? _event, actions
  55. 17604 actions = Array(actions).compact
  56. 17604 actions.empty? ? true : actions.include?(action)
  57. end
  58. # if changing name/type, the old card has no-longer-applicable set modules, so we create
  59. # a new card to determine whether events apply.
  60. # (note: cached condition card would ideally be cleared after all
  61. # conditions are reviewed)
  62. # @param old_sets [True/False] whether to use the old_sets
  63. 1 def set_condition_card old_sets
  64. 56250 return self if old_sets || no_current_action?
  65. 50659 @set_condition_card ||=
  66. 316 updating_sets? ? set_condition_card_with_new_set_modules : self
  67. end
  68. # existing card is being changed in a way that alters its sets
  69. 1 def updating_sets?
  70. 316 action == :update && real? && (type_id_is_changing? || name_is_changing?)
  71. end
  72. # prevents locking in set_condition_card
  73. 1 def no_current_action?
  74. 54259 return false if @current_action
  75. 3600 @set_condition_card = nil
  76. 3600 true
  77. end
  78. 1 def set_condition_card_with_new_set_modules
  79. 22 cc = Card.find id
  80. 22 cc.name = name
  81. 22 cc.type_id = type_id
  82. 22 cc.include_set_modules
  83. end
  84. 1 def changed_condition_applies? _event, db_columns
  85. 19151 return true unless action == :update
  86. 3813 db_columns = Array(db_columns).compact
  87. 3813 return true if db_columns.empty?
  88. 2046 db_columns.any? { |col| single_changed_condition_applies? col }
  89. end
  90. 1 alias_method :changing_condition_applies?, :changed_condition_applies?
  91. 1 def when_condition_applies? _event, block
  92. 9195 case block
  93. 19 when Proc then block.call(self)
  94. 4008 when Symbol then send block
  95. 5168 else true
  96. end
  97. end
  98. # "applies always means event can run
  99. # so if skip_condition_applies?, we do NOT skip
  100. 1 def skip_condition_applies? event, allowed
  101. 9204 return true unless (val = full_skip_hash[event.name.to_s])
  102. 9 allowed ? val.blank? : (val != :force)
  103. end
  104. 1 def trigger_condition_applies? event, required
  105. 9195 return true unless required
  106. full_trigger_hash[event.name.to_s].present?
  107. end
  108. 1 def single_changed_condition_applies? db_column
  109. 1075 return true unless db_column
  110. 1075 send "#{db_column}_is_changing?"
  111. end
  112. 1 def wrong_stage opts
  113. return false if director.stage_ok? opts
  114. if !stage
  115. "phase method #{method} called outside of event phases"
  116. else
  117. "#{opts.inspect} method #{method} called in stage #{stage}"
  118. end
  119. end
  120. 1 def wrong_action actn
  121. return false if on_condition_applies?(nil, actn)
  122. "on: #{actn} method #{method} called on #{action}"
  123. end
  124. 1 def full_skip_hash
  125. 9204 @full_skip_hash ||= act_skip_hash.merge skip_in_action_hash
  126. end
  127. 1 def act_skip_hash
  128. 387 (act_card || self).skip_hash
  129. end
  130. 1 def skip_in_action_hash
  131. 365 hash_with_value skip_in_action, true
  132. end
  133. 1 def full_trigger_hash
  134. @full_trigger_hash ||= act_trigger_hash.merge trigger_in_action_hash
  135. end
  136. 1 def trigger_in_action_hash
  137. hash_with_value trigger_in_action, true
  138. end
  139. 1 def act_trigger_hash
  140. (act_card || self).trigger_hash
  141. end
  142. 1 def hash_with_value array, value
  143. 550 Array.wrap(array).each_with_object({}) do |event, hash|
  144. hash[event.to_s] = value
  145. end
  146. end
  147. end;end;end;end;
  148. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/event_conditions.rb ~~

card/tmpsets/set/mod003-core/all/export.rb

40.0% lines covered

40 relevant lines. 16 lines covered and 24 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Export)
  4. #
  5. 1 module Export;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/export.rb"; end
  8. 2 module JsonFormat; module_parent.send :register_set_format, Card::Format::JsonFormat, self; extend Card::Set::AbstractFormat
  9. # returns an array of Hashes (each in export_item view)
  10. 1 view :export, cache: :never do
  11. exporting_uniques do
  12. Array.wrap(render_export_item).concat(export_items_in_view(:export)).flatten
  13. end
  14. end
  15. 1 def max_export_depth
  16. Env.params[:max_export_depth].present? ? Env.params[:max_export_depth].to_i : 2
  17. end
  18. # returns an array of Hashes (each in export_item view)
  19. 1 view :export_items, cache: :never do
  20. exporting_uniques do
  21. export_items_in_view(:export).flatten
  22. end
  23. end
  24. # returns Hash with the essentials needed to import a card into a new database
  25. 1 view :export_item do
  26. item = { name: card.name, type: card.type_name, content: card.content }
  27. item[:codename] = card.codename if card.codename
  28. track_exporting card
  29. item
  30. end
  31. 1 def export_items_in_view view
  32. within_max_depth do
  33. valid_items_for_export.map do |item|
  34. nest item, view: view
  35. end
  36. end
  37. end
  38. 1 def track_exporting card
  39. return unless @exported_keys
  40. @exported_keys << card.key
  41. end
  42. 1 def exporting_uniques
  43. @exported_keys ||= inherit(:exported_keys) || ::Set.new
  44. yield
  45. end
  46. # prevent recursion
  47. 1 def within_max_depth
  48. @export_depth ||= inherit(:export_depth).to_i + 1
  49. @export_depth > max_export_depth ? [] : yield
  50. end
  51. 1 def items_for_export
  52. nest_chunks.map do |chunk|
  53. next if chunk.try :main?
  54. chunk.referee_card
  55. end.compact
  56. end
  57. 1 def valid_items_for_export
  58. items_for_export.flatten.reject(&:blank?).uniq.find_all do |card|
  59. valid_export_card? card
  60. end
  61. end
  62. 1 def valid_export_card? ecard
  63. ecard.real? && !@exported_keys.include?(ecard.key)
  64. end
  65. end
  66. end;end;end;end;
  67. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/export.rb ~~

card/tmpsets/set/mod003-core/all/extended.rb

92.0% lines covered

25 relevant lines. 23 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Extended)
  4. #
  5. 1 module Extended;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/extended.rb"; end
  8. 1 def extended_item_cards context=nil
  9. 15 items = item_cards limit: "", context: (context || self).name
  10. 15 list = []
  11. 15 book = ::Set.new # avoid loops
  12. 15 extend_item_list items, list, book until items.empty?
  13. 15 list
  14. end
  15. 1 def extended_item_contents context=nil
  16. extended_item_cards(context).map(&:item_names).flatten
  17. end
  18. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  19. 1 delegate :extended_item_contents, to: :card
  20. end
  21. 1 private
  22. 1 def extend_item_list items, list, book
  23. 25 item = items.shift
  24. 25 return if already_extended? item, book
  25. 25 if item.collection?
  26. # keep items in order
  27. items.unshift(*item.item_cards)
  28. else # no further level of items
  29. 25 list << item
  30. end
  31. end
  32. 1 def already_extended? item, book
  33. 25 return true if book.include? item
  34. 25 book << item
  35. 25 false
  36. end
  37. # def extended_list context=nil
  38. # context = (context ? context.name : name)
  39. # args = { limit: "" }
  40. # item_cards(args.merge(context: context)).map do |x|
  41. # x.item_cards(args)
  42. # end.flatten.map do |x|
  43. # x.item_cards(args)
  44. # end.flatten.map do |y|
  45. # y.item_names(args)
  46. # end.flatten
  47. # # this could go on and on. more elegant to recurse until you don't have
  48. # # a collection
  49. # end
  50. end;end;end;end;
  51. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/extended.rb ~~

card/tmpsets/set/mod003-core/all/fetch.rb

79.59% lines covered

49 relevant lines. 39 lines covered and 10 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Fetch)
  4. #
  5. # = Card#fetch
  6. #
  7. 1 module Fetch;
  8. 1 extend Card::Set
  9. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/fetch.rb"; end
  10. # A multipurpose retrieval operator that integrates caching, database lookups,
  11. # and "virtual" card construction
  12. 1 module ClassMethods
  13. # Look for cards in
  14. # * cache
  15. # * database
  16. # * virtual cards
  17. #
  18. # @param args [Integer, String, Card::Name, Symbol, Array]
  19. # one or more of the three unique identifiers
  20. # 1. a numeric id (Integer)
  21. # 2. a name/key (String or Card::Name)
  22. # 3. a codename (Symbol)
  23. # If you pass more then one mark or an array of marks they get joined with a '+'.
  24. # The final argument can be a hash to set the following options
  25. # :skip_virtual Real cards only
  26. # :skip_modules Don't load Set modules
  27. # :look_in_trash Return trashed card objects
  28. # :local_only Use only local cache for lookup and storing
  29. # new: { opts for Card#new } Return a new card when not found
  30. # @return [Card]
  31. 1 def fetch *args
  32. 52110 Card::Fetch.new(*args)&.retrieve_or_new
  33. rescue ActiveModel::RangeError => _e
  34. return Card.new name: "card id out of range: #{f.mark}"
  35. end
  36. # fetch only real (no virtual) cards
  37. #
  38. # @param mark - see #fetch
  39. # @return [Card]
  40. 1 def [] *mark
  41. 1979 fetch(*mark, skip_virtual: true)
  42. end
  43. # fetch real cards without set modules loaded. Should only be used for simple attributes
  44. # @example
  45. # quick_fetch "A", :self, :structure
  46. #
  47. # @param mark - see #fetch
  48. # @return [Card]
  49. 1 def quick_fetch *mark
  50. 34186 fetch(*mark, skip_virtual: true, skip_modules: true)
  51. end
  52. # @return [Card]
  53. 1 def fetch_from_cast cast
  54. fetch_args = cast[:id] ? [cast[:id].to_i] : [cast[:name], { new: cast }]
  55. fetch *fetch_args
  56. end
  57. #----------------------------------------------------------------------
  58. # ATTRIBUTE FETCHING
  59. # The following methods optimize fetching of specific attributes
  60. 1 def id cardish
  61. 9234 case cardish
  62. 6003 when Integer then cardish
  63. 83 when Card then cardish.id
  64. 1 when Symbol then Card::Codename.id cardish
  65. 3147 else fetch_id cardish
  66. end
  67. end
  68. # @param mark_parts - see #fetch
  69. # @return [Integer]
  70. 1 def fetch_id *mark_parts
  71. 26251 mark = Card::Fetch.new(*mark_parts)&.mark
  72. 26251 mark.is_a?(Integer) ? mark : quick_fetch(mark.to_s)&.id
  73. end
  74. # @param mark - see #fetch
  75. # @return [Card::Name]
  76. 1 def fetch_name *mark
  77. 1217 if (card = quick_fetch(*mark))
  78. 1166 card.name
  79. 51 elsif block_given?
  80. yield.to_name
  81. end
  82. rescue ActiveModel::RangeError => _e
  83. block_given? ? yield.to_name : nil
  84. rescue Card::Error::CodenameNotFound => e
  85. block_given? ? yield.to_name : raise(e)
  86. end
  87. # @param mark - see #fetch
  88. # @return [Integer]
  89. 1 def fetch_type_id mark
  90. 25 quick_fetch(mark)&.type_id
  91. end
  92. end
  93. #----------------------------------------------------------------------
  94. # INSTANCE METHODS
  95. # fetching from the context of a card
  96. 1 def fetch traits, opts={}
  97. 473 opts[:new][:supercard] = self if opts[:new]
  98. 473 Array.wrap(traits).inject(self) do |card, trait|
  99. 473 Card.fetch card.name.trait(trait), opts
  100. end
  101. end
  102. 1 def newish opts
  103. 22 reset_patterns
  104. 22 Card.with_normalized_new_args opts do |norm_opts|
  105. 22 handle_type norm_opts do
  106. 22 assign_attributes norm_opts
  107. 22 self.name = name # trigger superize_name
  108. end
  109. end
  110. end
  111. 1 def refresh force=false
  112. 28 return self unless force || frozen? || readonly?
  113. return unless id
  114. fresh_card = self.class.find id
  115. fresh_card.include_set_modules
  116. fresh_card
  117. end
  118. end;end;end;end;
  119. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/fetch.rb ~~

card/tmpsets/set/mod003-core/all/fetch_helper.rb

100.0% lines covered

22 relevant lines. 22 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (FetchHelper)
  4. #
  5. 1 module FetchHelper;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/fetch_helper.rb"; end
  8. 1 module ClassMethods
  9. # a fetch method to support the needs of the card controller.
  10. # should be in Decko?
  11. 1 def controller_fetch args
  12. 36 card_opts = controller_fetch_opts args
  13. 36 if args[:action] == "create"
  14. # FIXME: we currently need a "new" card to catch duplicates
  15. # (otherwise save will just act like a normal update)
  16. # We may need a "#create" instance method to handle this checking?
  17. 9 Card.new card_opts
  18. else
  19. 27 standard_controller_fetch args, card_opts
  20. end
  21. end
  22. 1 private
  23. 1 def standard_controller_fetch args, card_opts
  24. 27 mark = args[:mark] || card_opts[:name]
  25. 27 card = Card.fetch mark, skip_modules: true,
  26. look_in_trash: args[:look_in_trash],
  27. new: card_opts
  28. 27 card.assign_attributes card_opts if args[:assign] && card&.real?
  29. 27 card&.include_set_modules
  30. 27 card
  31. end
  32. 1 def controller_fetch_opts args
  33. 36 opts = Env.hash args[:card]
  34. 36 opts[:type] ||= args[:type] if args[:type]
  35. # for /new/:type shortcut. we should handle in routing and deprecate this
  36. 36 opts[:name] ||= Card::Name.url_key_to_standard args[:mark]
  37. 36 opts
  38. end
  39. end
  40. end;end;end;end;
  41. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/fetch_helper.rb ~~

card/tmpsets/set/mod003-core/all/haml.rb

75.86% lines covered

29 relevant lines. 22 lines covered and 7 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Haml)
  4. #
  5. 1 module Haml;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/haml.rb"; end
  8. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  9. 1 include Card::Set::Format::HamlPaths
  10. 1 define_method :the_scope do
  11. set_scope
  12. end
  13. 1 define_method :haml_scope do
  14. set_scope
  15. end
  16. # Renders haml templates. The haml template can be passed as string or
  17. # block or a symbol that refers to a view template.
  18. # @param args [Hash, String, Symbol]
  19. # If a symbol is given then a template is expected in the corresponding view
  20. # directory.
  21. # @return [String] rendered haml as HTML
  22. # @example render a view template
  23. # # view/type/basic/my_template.haml:
  24. # %p
  25. # Hi
  26. # = name
  27. #
  28. # # set/type/basic.rb:
  29. # view :my_view do
  30. # haml :my_template, name: "Joe: # => "<p>Hi Joe<p/>"
  31. # end
  32. # @example use a block to pass haml
  33. # haml name: "Joe" do
  34. # <<-HAML.strip_heredoc
  35. # %p
  36. # Hi
  37. # = name
  38. # HAML
  39. # # => <p>Hi Joe</p>
  40. # @example create a slot in haml code
  41. # - haml_wrap do
  42. # %p
  43. # some haml
  44. 1 def haml *args, &block
  45. 102 if args.first.is_a? Symbol
  46. 102 process_haml_template(*args)
  47. else
  48. process_haml(*args, &block)
  49. end
  50. end
  51. 1 def haml_partial partial, locals={}
  52. locals[:template_path] ||= @template_path
  53. process_haml_template "_#{partial}".to_sym, locals
  54. end
  55. 1 private
  56. 1 def process_haml *args
  57. args.unshift yield if block_given?
  58. haml_to_html(*args)
  59. end
  60. 1 def process_haml_template template_name, *args
  61. 102 locals = args.first || {}
  62. 102 path = identify_template_path template_name, locals
  63. 102 with_template_path path do
  64. 102 haml_to_html ::File.read(path), *args
  65. end
  66. # rescue => e
  67. # raise Card::Error, "HAML error #{template_name}: #{e.message}\n#{e.backtrace}"
  68. end
  69. 1 def identify_template_path view, locals={}
  70. 102 base_path = locals.delete(:template_path) || caller_locations[2].path
  71. 102 haml_template_path view, base_path
  72. end
  73. end
  74. end;end;end;end;
  75. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/haml.rb ~~

card/tmpsets/set/mod003-core/all/i18n.rb

100.0% lines covered

9 relevant lines. 9 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (I18n)
  4. #
  5. 1 module I18n;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/i18n.rb"; end
  8. 1 def tr key, args={}
  9. 2 ::I18n.t key, args.reverse_merge(scope: Card::Set.scope(caller))
  10. end
  11. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  12. 1 def tr key, args={}
  13. 46 ::I18n.t key, args.reverse_merge(scope: Card::Set.scope(caller))
  14. end
  15. end
  16. end;end;end;end;
  17. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/i18n.rb ~~

card/tmpsets/set/mod003-core/all/initialize.rb

100.0% lines covered

49 relevant lines. 49 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Initialize)
  4. #
  5. 1 module Initialize;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/initialize.rb"; end
  8. 1 JUNK_INIT_ARGS = %w[missing skip_virtual id].freeze
  9. 1 module ClassMethods
  10. 1 def new args={}, _options={}
  11. 2899 with_normalized_new_args args do |normalized_args|
  12. 2899 super normalized_args
  13. end
  14. end
  15. 1 def with_normalized_new_args args={}
  16. 2921 args = (args || {}).stringify_keys
  17. 2921 delete_junk_args args
  18. 2921 normalize_type_args args
  19. 2921 normalize_content_args args
  20. 2921 yield args
  21. end
  22. 1 private
  23. 1 def delete_junk_args args
  24. 11684 JUNK_INIT_ARGS.each { |a| args.delete(a) }
  25. end
  26. 1 def normalize_type_args args
  27. 8763 %w[type type_code].each { |k| args.delete(k) if args[k].blank? }
  28. end
  29. 1 def normalize_content_args args
  30. 2921 args.delete("content") if args["attach"] # should not be handled here!
  31. 2921 args["db_content"] = args.delete "content" if args["content"]
  32. end
  33. end
  34. 1 def initialize args={}
  35. 2899 args["name"] = initial_name args["name"]
  36. 2899 handle_set_modules args do
  37. 2899 handle_type args do
  38. 2899 super args # ActiveRecord #initialize
  39. end
  40. end
  41. 2899 self
  42. end
  43. 1 def handle_set_modules args
  44. 2899 skip_modules = args.delete "skip_modules"
  45. 2899 yield
  46. 2899 include_set_modules unless skip_modules
  47. end
  48. 1 def handle_type args
  49. 2921 type_lookup = args["type_lookup"]
  50. 2921 @supercard = args.delete "supercard"
  51. 2921 yield
  52. 2921 type_id_from_template if type_lookup == :force || (!type_id && type_lookup != :skip)
  53. end
  54. 1 def initial_name name
  55. 2899 name.is_a?(String) ? name : Card::Name[name].to_s
  56. end
  57. 1 def include_set_modules
  58. 10409 return self if @set_mods_loaded
  59. 4197 set_modules.each do |m|
  60. 7228 singleton_class.send :include, m
  61. end
  62. 4197 assign_set_specific_attributes
  63. 4197 @uncacheable = @set_mods_loaded = true
  64. 4197 self
  65. end
  66. 1 def uncacheable?
  67. 6755 @uncacheable == true
  68. end
  69. end;end;end;end;
  70. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/initialize.rb ~~

card/tmpsets/set/mod003-core/all/item.rb

45.45% lines covered

77 relevant lines. 35 lines covered and 42 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Item)
  4. #
  5. 1 module Item;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/item.rb"; end
  8. 1 def item_names _args={}
  9. format._render_raw.split(/[,\n]/)
  10. end
  11. 1 def item_cards _args={} # FIXME: this is inconsistent with item_names
  12. 34 [self]
  13. end
  14. 1 def item_type
  15. nil
  16. end
  17. 1 def item_keys args={}
  18. item_names(args).map do |item|
  19. item.to_name.key
  20. end
  21. end
  22. 1 def item_count args={}
  23. item_names(args).size
  24. end
  25. 1 def items_to_content array
  26. 199 items = array.map { |i| standardize_item i }.reject(&:blank?)
  27. 20 self.content = items.to_pointer_content
  28. end
  29. 1 def standardize_item item
  30. 179 Card::Name[item]
  31. end
  32. 1 def include_item? item
  33. item_names.include? Card::Name[item]
  34. end
  35. 1 def add_item item
  36. return if include_item? item
  37. items_to_content(items_strings << item)
  38. end
  39. 1 def drop_item item
  40. item = Card::Name[item]
  41. return unless include_item? item
  42. items_to_content(item_names.reject { |i| i == item })
  43. end
  44. 1 def insert_item index, name
  45. new_names = item_names
  46. new_names.delete name
  47. new_names.insert index, name
  48. items_to_content new_names
  49. end
  50. 1 def replace_item old, new
  51. return unless include_item? old
  52. drop_item old
  53. add_item new
  54. end
  55. # I think the following should work as add_item...
  56. #
  57. 1 def add_id id
  58. add_item "~#{id}"
  59. end
  60. 1 def drop_id id
  61. drop_item "~#{id}"
  62. end
  63. 1 def insert_id index, id
  64. insert_item index, "~#{id}"
  65. end
  66. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  67. 1 def item_links _args={}
  68. raw(render_core).split(/[,\n]/)
  69. end
  70. 1 def nest_item cardish, options={}, &block
  71. options = item_view_options options
  72. options[:nest_name] = Card::Name[cardish].s
  73. nest cardish, options, &block
  74. end
  75. 1 def implicit_item_view
  76. view = voo_items_view || default_item_view
  77. Card::View.normalize view
  78. end
  79. 1 def voo_items_view
  80. return unless voo && (items = voo.items)
  81. items[:view]
  82. end
  83. 1 def default_item_view
  84. :name
  85. end
  86. 1 def item_view_options new_options={}
  87. options = (voo.items || {}).clone
  88. options = options.merge new_options
  89. options[:view] ||= implicit_item_view
  90. determine_item_view_options_type options
  91. options
  92. end
  93. 1 def determine_item_view_options_type options
  94. return if options[:type]
  95. type_from_rule = card.item_type
  96. options[:type] = type_from_rule if type_from_rule
  97. end
  98. 1 def listing listing_cards, item_args={}
  99. listing_cards.map do |item_card|
  100. nest_item item_card, item_args do |rendered, item_view|
  101. wrap_item rendered, item_view
  102. end
  103. end
  104. end
  105. 1 def wrap_item item, _args={}
  106. item # no wrap in base
  107. end
  108. end
  109. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  110. 1 def wrap_item rendered, item_view
  111. %(<div class="item-#{item_view}">#{rendered}</div>)
  112. end
  113. end
  114. end;end;end;end;
  115. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/item.rb ~~

card/tmpsets/set/mod003-core/all/layouts.rb

64.71% lines covered

17 relevant lines. 11 lines covered and 6 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Layouts)
  4. #
  5. 1 module Layouts;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/layouts.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 attr_reader :interior
  10. 1 def layout_nest
  11. wrap_main { interior }
  12. end
  13. 1 layout :pre do # {{_main|raw}}
  14. wrap_with :pre do
  15. layout_nest
  16. end
  17. end
  18. 1 layout :simple do
  19. layout_nest
  20. end
  21. 1 layout :no_side do # {{_main|open}}
  22. <<-HTML.strip_heredoc
  23. <header>#{nest :header, view: :core}</header>
  24. <article>#{layout_nest}</article>
  25. <footer>{nest :footer, view: :core}</footer>
  26. HTML
  27. end
  28. 1 layout :default do
  29. <<-HTML.strip_heredoc
  30. <header>#{nest :header, view: :core}</header>
  31. <article>#{layout_nest}</article>
  32. <aside>#{nest :sidebar, view: :core}</aside>
  33. <footer>{nest :footer, view: :core}</footer>
  34. HTML
  35. end
  36. end
  37. end;end;end;end;
  38. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/layouts.rb ~~

card/tmpsets/set/mod003-core/all/location_history.rb

100.0% lines covered

14 relevant lines. 14 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (LocationHistory)
  4. #
  5. 1 module LocationHistory;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/location_history.rb"; end
  8. 1 event :discard_deleted_locations, :finalize, on: :delete do
  9. 76 Env.discard_locations_for self
  10. 76 configure_successful_deletion if success.target == self
  11. end
  12. 1 event :save_current_location, before: :show_page, on: :read do
  13. 31 Env.save_location self
  14. end
  15. # TO DISCUSS: should this default behavior be directly in the controller?
  16. # Or at least in decko?
  17. 1 def configure_successful_deletion
  18. 22 if Env.ajax?
  19. 1 success.card = self
  20. 1 success.view = :unknown unless success.view
  21. else
  22. 21 success.target = :previous
  23. end
  24. end
  25. end;end;end;end;
  26. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/location_history.rb ~~

card/tmpsets/set/mod003-core/all/name.rb

90.23% lines covered

133 relevant lines. 120 lines covered and 13 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Name)
  4. #
  5. 1 module Name;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/name.rb"; end
  8. 1 require "uuid"
  9. 1 module ClassMethods
  10. 1 def uniquify_name name, rename=:new
  11. return name unless Card.exists? name
  12. uniq_name = generate_alternative_name name
  13. return uniq_name unless rename == :old
  14. rename!(name, uniq_name)
  15. name
  16. end
  17. 1 def generate_alternative_name name
  18. uniq_name = "#{name} 1"
  19. uniq_name.next! while Card.exists?(uniq_name)
  20. uniq_name
  21. end
  22. 1 def rename! oldname, newname
  23. Card[oldname].update! name: newname, update_referers: true
  24. end
  25. end
  26. 1 def name
  27. 96763 @name ||= left_id ? Card::Lexicon.lex_to_name([left_id, right_id]) : super.to_name
  28. end
  29. 1 def key
  30. 15008 @key ||= left_id ? name.key : super
  31. end
  32. 1 def name= newname
  33. 2979 @name = superize_name newname.to_name
  34. 2979 self.key = @name.key
  35. 2979 update_subcard_names @name
  36. 2979 write_attribute :name, (@name.simple? ? @name.s : nil)
  37. 2979 assign_side_ids
  38. 2979 @name
  39. end
  40. 1 def assign_side_ids
  41. 2979 if name.simple?
  42. 1558 self.left_id = self.right_id = nil
  43. else
  44. 1421 assign_side_id :left_id=, :left_name
  45. 1421 assign_side_id :right_id=, :right_name
  46. end
  47. end
  48. # assigns left_id and right_id based on names.
  49. # if side card is new, id is temporarily stored as -1
  50. 1 def assign_side_id side_id_equals, side_name
  51. 2842 side_id = Card::Lexicon.id(name.send(side_name)) || -1
  52. 2842 send side_id_equals, side_id
  53. end
  54. 1 def superize_name cardname
  55. 2979 return cardname unless @supercard
  56. 8 @raw_name = cardname.s
  57. 8 @supercard.subcards.rename key, cardname.key
  58. 8 update_superleft cardname
  59. 8 cardname.absolute_name @supercard.name
  60. end
  61. 1 def update_superleft cardname
  62. 100 @superleft = @supercard if cardname.field_of? @supercard.name
  63. end
  64. 1 def key= newkey
  65. 2979 return if newkey == key
  66. 2940 update_cache_key key do
  67. 2940 write_attribute :key, (name.simple? ? newkey : nil)
  68. 2940 @key = newkey
  69. end
  70. 2940 clean_patterns
  71. 2940 @key
  72. end
  73. 1 def clean_patterns
  74. 2940 return unless patterns?
  75. 15 reset_patterns
  76. 15 patterns
  77. end
  78. 1 def update_cache_key oldkey
  79. 2940 yield
  80. 2940 was_in_cache = Card.cache.soft.delete oldkey
  81. 2940 Card.write_to_soft_cache self if was_in_cache
  82. end
  83. 1 def update_subcard_names new_name, name_to_replace=nil
  84. 2981 return unless @subcards
  85. 15 subcards.each do |subcard|
  86. 2 update_subcard_name subcard, new_name, name_to_replace if subcard.new?
  87. end
  88. end
  89. 1 def update_subcard_name subcard, new_name, name_to_replace
  90. 2 name_to_replace ||= name_to_replace_for_subcard subcard, new_name
  91. 2 subcard.name = subcard.name.swap name_to_replace, new_name.s
  92. 2 subcard.update_subcard_names new_name, name # needed? shouldn't #name= trigger this?
  93. end
  94. 1 def name_to_replace_for_subcard subcard, new_name
  95. # if subcard has a relative name like +C
  96. # and self is a subcard as well that changed from +B to A+B then
  97. # +C should change to A+B+C. #replace doesn't work in this case
  98. # because the old name +B is not a part of +C
  99. 2 if subcard.name.starts_with_joint? && new_name.parts.first.present?
  100. 2 "".to_name
  101. else
  102. name
  103. end
  104. end
  105. 1 def autoname name
  106. 3 if Card.exists?(name) || Director.include?(name)
  107. 1 autoname name.next
  108. else
  109. 2 name
  110. end
  111. end
  112. # FIXME: use delegations and include all name functions
  113. 1 def simple?
  114. 8888 name.simple?
  115. end
  116. 1 def junction?
  117. 1952 name.junction?
  118. end
  119. 1 def raw_name
  120. @raw_name || name
  121. end
  122. 1 def left *args
  123. case
  124. 1262 when simple? then nil
  125. 166 when superleft then superleft
  126. when name_is_changing? && name.to_name.trunk_name == name_before_act.to_name
  127. nil # prevent recursion when, eg, renaming A+B to A+B+C
  128. else
  129. 970 Card.fetch name.left, *args
  130. end
  131. end
  132. 1 def right *args
  133. 5807 Card.fetch(name.right, *args) unless simple?
  134. end
  135. 1 def [] *args
  136. 641 case args[0]
  137. when Integer, Range
  138. 5 fetch_name = Array.wrap(name.parts[args[0]]).compact.join Card::Name.joint
  139. 5 Card.fetch(fetch_name, args[1] || {}) unless simple?
  140. else
  141. 636 super
  142. end
  143. end
  144. 1 def trunk *args
  145. 238 simple? ? self : left(*args)
  146. end
  147. 1 def tag *args
  148. 6 simple? ? self : Card.fetch(name.right, *args)
  149. end
  150. 1 def left_or_new args={}
  151. 185 left(args) || Card.new(args.merge(name: name.left))
  152. end
  153. # NOTE: for all these helpers, method returns *all* fields/children/descendants.
  154. # (Not just those current user has permission to read.)
  155. 1 def fields
  156. 26 field_ids.map { |id| Card[id] }
  157. end
  158. 1 def field_names
  159. field_ids.map { |id| Card::Name[id] }
  160. end
  161. 1 def field_ids
  162. 17 child_ids :left
  163. end
  164. 1 def each_child
  165. 106 child_ids.each do |id|
  166. 63 (child = Card[id]) && yield(child)
  167. # check should not be needed (remove after fixing data problems)
  168. end
  169. end
  170. # eg, A+B is a child of A and B
  171. 1 def child_ids side=nil
  172. 123 return [] unless id
  173. 123 side ||= name.simple? ? :part : :left_id
  174. 123 Auth.as_bot do
  175. 123 Card.search({ side => id, return: :id, limit: 0 }, "children of #{name}")
  176. end
  177. end
  178. 1 def each_descendant &block
  179. 29 each_child do |child|
  180. 11 yield child
  181. 11 child.each_descendant(&block)
  182. end
  183. end
  184. 1 def right_id= cardish
  185. 3011 write_card_or_id :right_id, cardish
  186. end
  187. 1 def left_id= cardish
  188. 3030 write_card_or_id :left_id, cardish
  189. end
  190. 1 def write_card_or_id attribute, cardish
  191. 17688 when_id_exists(cardish) { |id| write_attribute attribute, id }
  192. end
  193. 1 def when_id_exists cardish, &block
  194. 8844 if (card_id = Card.id cardish)
  195. 5675 yield card_id
  196. 3169 elsif cardish.is_a? Card
  197. 53 with_id_after_store cardish, &block
  198. else
  199. 3116 yield cardish # eg nil
  200. end
  201. end
  202. # subcards are usually saved after super cards;
  203. # after_store forces it to save the subcard first
  204. # and callback afterwards
  205. 1 def with_id_after_store subcard
  206. 53 add_subcard subcard
  207. 106 subcard.director.after_store { |card| yield card.id }
  208. end
  209. end;end;end;end;
  210. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/name.rb ~~

card/tmpsets/set/mod003-core/all/name_events.rb

80.26% lines covered

76 relevant lines. 61 lines covered and 15 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (NameEvents)
  4. #
  5. # STAGE: prepare to validate
  6. 1 module NameEvents;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/name_events.rb"; end
  9. 1 event :set_autoname, :prepare_to_validate, on: :create do
  10. 196 if name.blank? && (autoname_card = rule_card(:autoname))
  11. 2 self.name = autoname autoname_card.db_content
  12. # FIXME: should give placeholder in approve phase
  13. # and finalize/commit change in store phase
  14. 2 autoname_card.refresh.update_column :db_content, name
  15. end
  16. end
  17. # STAGE: validate
  18. 1 event :validate_name, :validate, on: :save, changed: :name do
  19. 217 validate_legality_of_name
  20. 217 return if errors.any?
  21. 216 Card.write_to_soft_cache self
  22. 216 validate_uniqueness_of_name
  23. end
  24. 1 event :validate_uniqueness_of_name, skip: :allowed do
  25. # validate uniqueness of name
  26. 216 return unless (existing_id = Card::Lexicon.id key) && existing_id != id
  27. # The above is a fast check but cannot detect if card is in trash
  28. # TODO: perform the following as a remote-only fetch (not yet supported)
  29. 17 return unless (existing_card = Card.where(id: existing_id, trash: false).take)
  30. 1 errors.add :name, tr(:error_name_exists, name: existing_card.name)
  31. end
  32. 1 event :validate_legality_of_name do
  33. 217 if name.length > 255
  34. errors.add :name, tr(:error_too_long, length: name.length)
  35. 217 elsif name.blank?
  36. 1 errors.add :name, tr(:error_blank_name)
  37. 216 elsif name.parts.include? ""
  38. errors.add :name, tr(:is_incomplete)
  39. 216 elsif !name.valid?
  40. errors.add :name, tr(:error_banned_characters, banned: Card::Name.banned_array * " ")
  41. 216 elsif changing_existing_tag_to_junction?
  42. errors.add :name, tr(:error_name_tag, name: name)
  43. end
  44. end
  45. 1 event :validate_key, after: :validate_name, on: :save do
  46. 217 if key.empty?
  47. 1 errors.add :key, tr(:error_blank_key) if errors.empty?
  48. 216 elsif key != name.key
  49. errors.add :key, tr(:error_wrong_key, key: key, name: name)
  50. end
  51. end
  52. # STAGE: store
  53. 1 event :expire_old_name, :store, changed: :name, on: :update do
  54. 18 Director.expirees << name_before_act
  55. end
  56. 1 event :update_lexicon_on_create, :finalize, changed: :name, on: :create do
  57. 189 Card::Lexicon.add self
  58. end
  59. 1 event :update_lexicon_on_rename, :finalize, changed: :name, on: :update do
  60. 18 Card::Lexicon.update self
  61. end
  62. 1 def lex
  63. 207 simple? ? name : [left_id, right_id]
  64. end
  65. 1 def old_lex
  66. 18 if (old_left_id = left_id_before_act)
  67. [old_left_id, right_id_before_act]
  68. else
  69. 18 name_before_act
  70. end
  71. end
  72. 1 event :prepare_left_and_right, :store, changed: :name, on: :save do
  73. 207 return if name.simple?
  74. 75 prepare_side :left
  75. 75 prepare_side :right
  76. end
  77. 1 def prepare_side side
  78. 150 side_id = send "#{side}_id"
  79. 150 sidename = name.send "#{side}_name"
  80. 150 prepare_obstructed_side(side, side_id, sidename) ||
  81. prepare_new_side(side, side_id, sidename)
  82. end
  83. 1 def prepare_new_side side, side_id, sidename
  84. 150 return unless side_id == -1 || !Card[side_id]&.real?
  85. 83 sidecard = Director.card(sidename) || add_subcard(sidename)
  86. 83 send "#{side}_id=", sidecard
  87. end
  88. 1 def prepare_obstructed_side side, side_id, sidename
  89. 150 return unless side_id && side_id == id
  90. clear_name sidename
  91. send "#{side}_id=", add_subcard(sidename)
  92. true
  93. end
  94. 1 private
  95. 1 def changing_existing_tag_to_junction?
  96. 216 return false unless changing_name_to_junction?
  97. name_in_use_as_tag?
  98. end
  99. 1 def name_in_use_as_tag?
  100. !Card.where(right_id: id, trash: false).take.nil?
  101. end
  102. 1 def changing_name_to_junction?
  103. 216 name.junction? && simple?
  104. end
  105. 1 def old_name_in_way? sidecard
  106. real? && sidecard&.simple? && id == sidecard&.id
  107. end
  108. 1 def clear_name name
  109. # move the current card out of the way, in case the new name will require
  110. # re-creating a card with the current name, ie. A -> A+B
  111. Card.where(id: id).update_all(name: nil, key: nil, left_id: nil, right_id: nil)
  112. Card.expire name
  113. Card::Lexicon.cache.reset # probably overkill, but this for an edge case...
  114. # Card::Lexicon.delete id, key
  115. end
  116. end;end;end;end;
  117. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/name_events.rb ~~

card/tmpsets/set/mod003-core/all/observer.rb

93.75% lines covered

16 relevant lines. 15 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Observer)
  4. #
  5. 1 module Observer;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/observer.rb"; end
  8. 1 %i[create update delete].each do |action|
  9. 3 event "observer_#{action}".to_sym, :integrate, on: action do
  10. 314 execute_card_events on: action
  11. end
  12. end
  13. 1 event :cache_delete_card_events, :store, on: :delete do
  14. 76 @card_event_cache = event_cards :on_delete
  15. end
  16. 1 def execute_card_events args
  17. 314 setting = "on_#{args[:on]}".to_sym
  18. 314 event_cards(setting).each do |event_card|
  19. event_card.deliver self
  20. end
  21. end
  22. 1 def event_cards setting
  23. 390 @card_event_cache ||
  24. 314 ((event_rule = rule_card(setting)) && event_rule.extended_item_cards) ||
  25. []
  26. end
  27. end;end;end;end;
  28. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/observer.rb ~~

card/tmpsets/set/mod003-core/all/pattern.rb

93.94% lines covered

33 relevant lines. 31 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Pattern)
  4. #
  5. 1 module Pattern;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/pattern.rb"; end
  8. 1 def patterns?
  9. 9676 defined? @patterns
  10. end
  11. 1 def all_patterns
  12. 55154 @all_patterns ||= set_patterns.map { |sub| sub.new self }.compact
  13. end
  14. # new cards do not
  15. 1 def patterns
  16. 5752 @patterns ||= (new_card? ? all_patterns[1..-1] : all_patterns)
  17. end
  18. 1 def reset_patterns
  19. # Rails.logger.info "resetting patterns: #{name}"
  20. 4158 @patterns = @all_patterns = nil
  21. 4158 @template = @virtual = nil
  22. 4158 @set_mods_loaded = @set_modules = @set_names = @rule_set_keys = nil
  23. 4158 @junction_only = nil # only applies to set cards
  24. 4158 true
  25. end
  26. 1 def safe_set_keys
  27. 130 patterns.map(&:safe_key).reverse * " "
  28. end
  29. 1 def set_modules
  30. 4198 @set_modules ||= all_patterns[0..-2].reverse.map(&:module_list).flatten.compact
  31. end
  32. 1 def set_format_modules klass
  33. 1849 @set_format_modules ||= {}
  34. 1849 @set_format_modules[klass] =
  35. all_patterns[0..-2].reverse.map do |pattern|
  36. 6002 pattern.format_module_list klass
  37. end.flatten.compact
  38. end
  39. 1 def set_names
  40. 31 @set_names = patterns.map(&:to_s) if @set_names.nil?
  41. 31 @set_names
  42. end
  43. 1 def in_set? set_module
  44. patterns.map(&:module_key).include? set_module.shortname
  45. end
  46. 1 def rule_set_keys
  47. 7009 @rule_set_keys ||= patterns.map(&:rule_set_key).compact
  48. end
  49. 1 def include_module? set
  50. singleton_class&.include? set
  51. end
  52. end;end;end;end;
  53. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/pattern.rb ~~

card/tmpsets/set/mod003-core/all/permissions.rb

88.8% lines covered

125 relevant lines. 111 lines covered and 14 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Permissions)
  4. #
  5. 1 module Permissions;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/permissions.rb"; end
  8. 1 module ClassMethods
  9. 1 def repair_all_permissions
  10. Card.where("(read_rule_class is null or read_rule_id is null) and trash is false")
  11. .each do |broken_card|
  12. broken_card.include_set_modules
  13. broken_card.repair_permissions!
  14. end
  15. end
  16. end
  17. 1 def repair_permissions!
  18. rule_id, rule_class = permission_rule_id_and_class :read
  19. update_columns read_rule_id: rule_id, read_rule_class: rule_class
  20. end
  21. # ok? and ok! are public facing methods to approve one action at a time
  22. #
  23. # fetching: if the optional :trait parameter is supplied, it is passed
  24. # to fetch and the test is perfomed on the fetched card, therefore:
  25. #
  26. # trait: :account would fetch this card plus a tag codenamed :account
  27. # trait: :roles, new: {} would initialize a new card with default ({})
  28. # options.
  29. 1 def ok? action
  30. 2267 @ok ||= {}
  31. 2267 aok = @ok[Auth.as_id] ||= {}
  32. 2267 if (cached = aok[action])
  33. 310 cached
  34. else
  35. 1957 aok[action] = send "ok_to_#{action}"
  36. end
  37. end
  38. 1 def ok! action
  39. 1 raise Card::Error::PermissionDenied, self unless ok? action
  40. end
  41. 1 def who_can action
  42. 1301 permission_rule_card(action).item_cards.map(&:id)
  43. end
  44. 1 def anyone_can? action
  45. who_can(action).include? AnyoneID
  46. end
  47. 1 def direct_rule_card action
  48. 234 direct_rule_id = rule_card_id action
  49. 234 require_permission_rule! direct_rule_id, action
  50. 234 Card.quick_fetch direct_rule_id
  51. end
  52. 1 def permission_rule_id action
  53. 1721 if junction? && rule(action).match?(/^\[?\[?_left\]?\]?$/)
  54. 185 left_permission_rule_id action
  55. else
  56. 1536 rule_card_id(action)
  57. end
  58. end
  59. 1 def permission_rule_id_and_class action
  60. 234 [permission_rule_id(action), direct_rule_card(action).rule_class_name]
  61. end
  62. 1 def left_permission_rule_id action
  63. 185 lcard = left_or_new(skip_virtual: true, skip_modules: true)
  64. 185 if action == :create && lcard.real? && lcard.action != :create
  65. 6 action = :update
  66. end
  67. 185 lcard.permission_rule_id action
  68. end
  69. 1 def permission_rule_card action
  70. 1301 Card.fetch permission_rule_id(action)
  71. end
  72. 1 def require_permission_rule! rule_id, action
  73. 234 return if rule_id
  74. # RULE missing. should not be possible.
  75. # generalize this to handling of all required rules
  76. errors.add :permission_denied, tr(:error_no_action_rule, action: action, name: name)
  77. raise Card::Error::PermissionDenied, self
  78. end
  79. 1 def rule_class_name
  80. 234 trunk.type_id == SetID ? name.trunk_name.tag : nil
  81. end
  82. 1 def you_cant what
  83. 52 "You don't have permission to #{what}"
  84. end
  85. 1 def deny_because why
  86. 52 @permission_errors << why if @permission_errors
  87. 52 false
  88. end
  89. 1 def permitted? action
  90. 1519 return false if Card.config.read_only # :read does not call #permit
  91. 1519 return true if Auth.always_ok?
  92. 1296 Auth.as_card.among? who_can(action)
  93. end
  94. 1 def permit action, verb=nil
  95. # not called by ok_to_read
  96. 1517 if Card.config.read_only
  97. deny_because "Currently in read-only mode"
  98. return false
  99. end
  100. 1517 return true if permitted? action
  101. 47 verb ||= action.to_s
  102. 47 deny_because you_cant("#{verb} #{name.present? ? name : 'this'}")
  103. end
  104. 1 def ok_to_create
  105. 1378 return false unless permit :create
  106. 1340 return true if simple?
  107. 80 %i[left right].each do |side|
  108. # left is supercard; create permissions will get checked there.
  109. 160 next if side == :left && superleft
  110. 126 part_card = send side, new: {}
  111. # if no card, there must be other errors
  112. 126 next unless part_card && part_card.new_card?
  113. 59 unless part_card.ok? :create
  114. deny_because you_cant("create #{part_card.name}")
  115. return false
  116. end
  117. end
  118. 80 true
  119. end
  120. 1 def ok_to_read
  121. 368 return true if Auth.always_ok?
  122. 338 self.read_rule_id ||= permission_rule_id :read
  123. 338 return true if Auth.as_card.read_rules_hash[read_rule_id]
  124. 5 deny_because you_cant "read this"
  125. end
  126. 1 def ok_to_update
  127. 60 return false unless permit(:update)
  128. 53 return true unless type_id_changed? && !permitted?(:create)
  129. deny_because you_cant("change to this type (need create permission)")
  130. end
  131. 1 def ok_to_delete
  132. 79 permit :delete
  133. end
  134. # don't know why we introduced this
  135. # but we have to preserve read rules to make
  136. # delete acts visible in recent changes -pk
  137. # event :clear_read_rule, :store, on: :delete do
  138. # self.read_rule_id = self.read_rule_class = nil
  139. # end
  140. 1 event :set_read_rule, :store,
  141. on: :save, changed: %i[type_id name] do
  142. 208 read_rule_id, read_rule_class = permission_rule_id_and_class(:read)
  143. 208 self.read_rule_id = read_rule_id
  144. 208 self.read_rule_class = read_rule_class
  145. end
  146. 1 event :set_field_read_rules,
  147. after: :set_read_rule, on: :update, changed: :type_id do
  148. # find all cards with me as trunk and update their read_rule
  149. # (because of *type plus right)
  150. # skip if name is updated because will already be resaved
  151. 1 each_field_as_bot do |field|
  152. 1 field.refresh.update_read_rule
  153. end
  154. end
  155. 1 def update_field_read_rules
  156. 26 return unless type_id_changed? || read_rule_id_changed?
  157. 16 each_field_as_bot do |field|
  158. 8 field.update_read_rule if field.rule(:read) == "_left"
  159. end
  160. end
  161. 1 def each_field_as_bot
  162. 17 Auth.as_bot do
  163. 26 fields.each { |field| yield field }
  164. end
  165. end
  166. 1 def without_timestamps
  167. 26 Card.record_timestamps = false
  168. 26 yield
  169. ensure
  170. 26 Card.record_timestamps = true
  171. end
  172. 1 event :update_read_rule do
  173. 26 without_timestamps do
  174. 26 reset_patterns # why is this needed?
  175. 26 rcard_id, rclass = permission_rule_id_and_class :read
  176. # these two are just to make sure vals are correct on current object
  177. 26 self.read_rule_id = rcard_id
  178. 26 self.read_rule_class = rclass
  179. 26 Card.where(id: id).update_all read_rule_id: rcard_id,
  180. read_rule_class: rclass
  181. 26 expire :hard
  182. 26 update_field_read_rules
  183. end
  184. end
  185. 1 def add_to_read_rule_update_queue updates
  186. @read_rule_update_queue = Array.wrap(@read_rule_update_queue).concat updates
  187. end
  188. 1 event :check_permissions, :validate do
  189. 323 track_permission_errors do
  190. 323 ok? action_for_permission_check
  191. end
  192. end
  193. 1 def action_for_permission_check
  194. 323 commenting? ? :update : action
  195. end
  196. 1 def track_permission_errors
  197. 323 @permission_errors = []
  198. 323 result = yield
  199. 329 @permission_errors.each { |msg| errors.add :permission_denied, msg }
  200. 323 @permission_errors = nil
  201. 323 result
  202. end
  203. end;end;end;end;
  204. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/permissions.rb ~~

card/tmpsets/set/mod003-core/all/references.rb

93.55% lines covered

93 relevant lines. 87 lines covered and 6 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (References)
  4. #
  5. # frozen_string_literal: true
  6. # Cards can refer to other cards in their content, eg via links and nests.
  7. 1 module References;
  8. 1 extend Card::Set
  9. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/references.rb"; end
  10. # The card that refers is the "referer", the card that is referred to is
  11. # the "referee". The reference itself has its own class (Card::Reference),
  12. # which handles id-based reference tracking.
  13. 1 PARTIAL_REF_CODE = "P".freeze
  14. # cards that refer to self
  15. 1 def referers
  16. 53 referer_cards_from_references references_in
  17. end
  18. # cards that include self
  19. 1 def nesters
  20. referer_cards_from_references references_in.where(ref_type: "I")
  21. end
  22. 1 def referer_cards_from_references references
  23. 53 references.map(&:referer_id).uniq.map(&Card.method(:fetch)).compact
  24. end
  25. # cards that self refers to
  26. 1 def referees
  27. referees_from_references references_out
  28. end
  29. # cards that self includes
  30. 1 def nestees
  31. referees_from_references references_out.where(ref_type: "I")
  32. end
  33. 1 def referees_from_references references
  34. references.map(&:referee_key).uniq.map { |key| Card.fetch key, new: {} }
  35. end
  36. # cards that refer to self by name
  37. # (finds cards not yet linked by id)
  38. 1 def name_referers
  39. Card.joins(:references_out).where card_references: { referee_key: key }
  40. end
  41. # replace references in card content
  42. 1 def replace_reference_syntax old_name, new_name
  43. 11 obj_content = Card::Content.new content, self
  44. 11 obj_content.find_chunks(Card::Content::Chunk::Reference).select do |chunk|
  45. 36 next unless (old_ref_name = chunk.referee_name)
  46. 36 next unless (new_ref_name = old_ref_name.swap old_name, new_name)
  47. 36 chunk.referee_name = chunk.replace_reference old_name, new_name
  48. 36 refs = Card::Reference.where referee_key: old_ref_name.key
  49. 36 refs.update_all referee_key: new_ref_name.key
  50. end
  51. 11 obj_content.to_s
  52. end
  53. # delete old references from this card's content, create new ones
  54. 1 def update_references_out
  55. 237 delete_references_out
  56. 237 create_references_out
  57. end
  58. # interpret references from this card's content and
  59. # insert entries in reference table
  60. 1 def create_references_out
  61. 237 ref_hash = {}
  62. 237 each_reference_out do |referee_name, ref_type|
  63. 241 interpret_reference ref_hash, referee_name, ref_type
  64. end
  65. 237 return if ref_hash.empty?
  66. 66 Card::Reference.mass_insert reference_values_array(ref_hash)
  67. end
  68. # delete references from this card
  69. 1 def delete_references_out
  70. 313 raise "id required to delete references" if id.nil?
  71. 313 Card::Reference.where(referer_id: id).delete_all
  72. end
  73. # interpretation phase helps to prevent duplicate references
  74. # results in hash like:
  75. # { referee1_key: [referee1_id, referee1_type2],
  76. # referee2_key...
  77. # }
  78. 1 def interpret_reference ref_hash, raw_referee_name, ref_type
  79. 275 with_normalized_referee raw_referee_name do |referee_name, referee_key, referee_id|
  80. 258 ref_hash[referee_key] ||= [referee_id]
  81. 258 ref_hash[referee_key] << ref_type
  82. 258 interpret_partial_references ref_hash, referee_name unless referee_id
  83. end
  84. end
  85. # Partial references are needed to track references to virtual cards.
  86. # For example a link to virual card [[A+*self]] won't have a referee_id,
  87. # but when A's name is changed we have to find and update that link.
  88. 1 def interpret_partial_references ref_hash, referee_name
  89. 28 return if referee_name.simple?
  90. 17 [referee_name.left, referee_name.right].each do |sidename|
  91. 34 interpret_reference ref_hash, sidename, PARTIAL_REF_CODE
  92. end
  93. end
  94. # translate interpreted reference hash into values array,
  95. # removing duplicate and unnecessary ref_types
  96. 1 def reference_values_array ref_hash
  97. 66 values = []
  98. 66 ref_hash.each do |referee_key, hash_val|
  99. 248 referee_id = hash_val.shift || "null"
  100. 248 ref_types = hash_val.uniq
  101. 248 ref_types.delete PARTIAL_REF_CODE if ref_types.size > 1
  102. # partial references are not necessary if there are explicit references
  103. 248 ref_types.each do |ref_type|
  104. 248 values << [id, referee_id, "'#{referee_key}'", "'#{ref_type}'"]
  105. end
  106. end
  107. 66 values
  108. end
  109. # invokes the given block for each reference in content with
  110. # the reference name and reference type
  111. 1 def each_reference_out
  112. 219 content_object.find_chunks(Card::Content::Chunk::Reference).each do |chunk|
  113. 94 yield chunk.referee_name, chunk.reference_code
  114. end
  115. end
  116. 1 def has_nests?
  117. content_object.has_chunk? Card::Content::Chunk::Nest
  118. end
  119. 1 def content_object
  120. 219 Card::Content.new content, self
  121. end
  122. 1 protected
  123. # test for updating referer content
  124. 1 event :prepare_referer_update, :validate, on: :update, changed: :name do
  125. 21 self.update_referers = ![nil, false, "false"].member?(update_referers)
  126. end
  127. # on rename, update names in cards that refer to self by name (as directed)
  128. 1 event :update_referer_content, :finalize, on: :update, when: :update_referers do
  129. 5 referers.each do |card|
  130. 11 next if card.structure
  131. 11 card.skip_event! :validate_renaming, :check_permissions
  132. 11 card.content = card.replace_reference_syntax name_before_act, name
  133. 11 attach_subcard card
  134. end
  135. end
  136. # on rename, when NOT updating referer content, update references to ensure
  137. # that partial references are correctly tracked
  138. # eg. A links to X+Y. if X+Y is renamed and we're not updating the link in A,
  139. # then we need to be sure that A has a partial reference
  140. 1 event :update_referer_references_out, :finalize,
  141. on: :update, when: :not_update_referers do
  142. 48 referers.map(&:update_references_out)
  143. end
  144. # when name changes, update references to card
  145. 1 event :refresh_references_in, :finalize, on: :save do
  146. 253 Card::Reference.unmap_referees id if action == :update && !update_referers
  147. 253 Card::Reference.map_referees key, id
  148. end
  149. # when content changes, update references to other cards
  150. 1 event :refresh_references_out, :finalize, on: :save, changed: :content do
  151. 221 update_references_out
  152. end
  153. # clean up reference table when card is deleted
  154. 1 event :clear_references, :finalize, on: :delete do
  155. 76 delete_references_out
  156. 76 Card::Reference.unmap_referees id
  157. end
  158. 1 def not_update_referers
  159. 53 !update_referers
  160. end
  161. 1 private
  162. 1 def with_normalized_referee referee_name
  163. 275 return unless referee_name # eg commented nest has no referee_name
  164. 275 referee_name = referee_name.to_name
  165. 275 referee_key = referee_name.key
  166. 275 return if referee_key == key # don't create self reference
  167. 258 yield referee_name, referee_key, Card::Lexicon.id(referee_name)
  168. end
  169. end;end;end;end;
  170. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/references.rb ~~

card/tmpsets/set/mod003-core/all/rename.rb

96.3% lines covered

27 relevant lines. 26 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Rename)
  4. #
  5. 1 module Rename;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/rename.rb"; end
  8. 1 event :rename_in_trash, after: :expire_old_name, on: :update do
  9. 26 existing_card = Card.find_by_key_and_trash name.key, true
  10. 26 return if !existing_card || existing_card == self
  11. 8 existing_card.name = existing_card.name + "*trash"
  12. 8 existing_card.rename_in_trash_without_callbacks
  13. 8 existing_card.save!
  14. end
  15. 1 event :validate_renaming, :validate, on: :update, changed: :name, skip: :allowed do
  16. 21 return if name_before_act&.to_name == name # just changing to new variant
  17. 20 errors.add :content, tr(:cannot_change_content) if content_is_changing?
  18. 20 errors.add :type, tr(:cannot_change_type) if type_is_changing?
  19. 20 detect_illegal_compound_names
  20. end
  21. 1 event :cascade_name_changes, :finalize, on: :update, changed: :name do
  22. 18 each_descendant do |d|
  23. 11 d.action = :update
  24. 11 update_referers ? d.update_referers : d.update_referer_references_out
  25. 11 d.refresh_references_in
  26. 11 d.refresh_references_out
  27. 11 d.expire
  28. end
  29. end
  30. 1 def changed_from_simple_to_compound?
  31. 20 name.compound? && name_before_act.to_name.simple?
  32. end
  33. 1 def detect_illegal_compound_names
  34. 20 return unless changed_from_simple_to_compound? && child_ids(:right).present?
  35. errors.add :name, "illegal name change; existing names end in +#{name_before_act}"
  36. end
  37. end;end;end;end;
  38. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/rename.rb ~~

card/tmpsets/set/mod003-core/all/rules.rb

78.26% lines covered

46 relevant lines. 36 lines covered and 10 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Rules)
  4. #
  5. 1 module Rules;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/rules.rb"; end
  8. 1 def rule setting_code
  9. 220 rule_card(setting_code, skip_modules: true)&.db_content
  10. end
  11. 1 def rule_card setting_code, options={}
  12. 5177 Card.fetch rule_card_id(setting_code), options
  13. end
  14. 1 def rule_card_id setting_code
  15. 6947 rule_id_lookup Card::Rule.rule_cache, setting_code
  16. end
  17. 1 def preference setting_code, user=nil
  18. 62 preference_card(setting_code, user, skip_modules: true)&.db_content
  19. end
  20. 1 def preference_card setting_code, user=nil, options={}
  21. 62 Card.fetch preference_card_id(setting_code, user), options
  22. end
  23. 1 def preference_card_id setting_code, user=nil
  24. 62 return unless (user_id = preference_user_id user)
  25. 62 rule_id_lookup Card::Rule.preference_cache,
  26. "#{setting_code}+#{user_id}",
  27. "#{setting_code}+#{AllID}"
  28. end
  29. 1 def is_rule?
  30. 5260 is_standard_rule? || is_preference?
  31. end
  32. 1 def is_standard_rule?
  33. 5260 (r = right(skip_modules: true)) &&
  34. r.type_id == SettingID &&
  35. 468 (l = left(skip_modules: true)) &&
  36. l.type_id == SetID
  37. end
  38. 1 def is_preference?
  39. 4866 name.parts.length > 2 &&
  40. 383 (r = right(skip_modules: true)) &&
  41. r.type_id == SettingID &&
  42. 5 (set = self[0..-3, skip_modules: true]) &&
  43. set.type_id == SetID &&
  44. (user = self[-2, skip_modules: true]) &&
  45. (user.type_id == UserID || user.codename == :all)
  46. end
  47. # FIXME: move to a better place (if still needed) and use codenames
  48. 1 def related_sets with_self=false
  49. # refers to sets that users may configure from the current card -
  50. # NOT to sets to which the current card belongs
  51. sets = []
  52. sets << ["#{name}+*self", Card::Set::Self.label(name)] if with_self
  53. if known? && name.simple?
  54. sets << ["#{name}+*right", Card::Set::Right.label(name)]
  55. end
  56. sets
  57. end
  58. 1 private
  59. 1 def preference_user_id user
  60. 62 case user
  61. 62 when Integer then user;
  62. when Card then user
  63. when nil then Auth.current_id
  64. else
  65. raise Card::ServerError, "invalid preference user"
  66. end
  67. end
  68. 1 def rule_id_lookup lookup_hash, cache_suffix, fallback_suffix=nil
  69. 7009 rule_set_keys.each do |rule_set_key|
  70. 25234 rule_id = lookup_hash["#{rule_set_key}+#{cache_suffix}"]
  71. 25234 rule_id ||= fallback_suffix && lookup_hash["#{rule_set_key}+#{fallback_suffix}"]
  72. 25234 return rule_id if rule_id
  73. end
  74. nil
  75. end
  76. end;end;end;end;
  77. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/rules.rb ~~

card/tmpsets/set/mod003-core/all/states.rb

80.0% lines covered

35 relevant lines. 28 lines covered and 7 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (States)
  4. #
  5. # All cards have one (and only one) of these three states: real, virtual, and unknown.
  6. #
  7. # - *real* cards are stored in the database (but not in the trash) and have a unique id.
  8. # - *virtual* cards are not real, but they act real based on rules. For example,
  9. # Home+*editors does a search for all the users who have edited the "Home" card.
  10. # There are many other similar cards that search for things like references, children,
  11. # etc. But we don't store all these cards in the database; we generate them dynamically
  12. 1 module States;
  13. 1 extend Card::Set
  14. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/states.rb"; end
  15. # based on the names.
  16. # - *unknown* cards are everything else.
  17. #
  18. # These states are frequently grouped as follows:
  19. #
  20. # - *known* cards are either _real_ or _virtual_
  21. # - *new* (or *unreal*) cards are either _unknown_ or _virtual_
  22. 1 module ClassMethods
  23. 1 def real? mark
  24. 35 quick_fetch(mark).present?
  25. end
  26. 1 alias exist? real?
  27. 1 alias exists? real?
  28. 1 def known? mark
  29. 160 fetch(mark).present?
  30. end
  31. end
  32. # @return [Symbol] :real, :virtual, or :unknown
  33. 1 def state anti_fishing=true
  34. case
  35. when !known? then :unknown
  36. when anti_fishing && !ok?(:read) then :unknown
  37. when real? then :real
  38. when virtual? then :virtual
  39. else :wtf
  40. end
  41. end
  42. # @return [True/False]
  43. 1 def real?
  44. 1820 !unreal?
  45. end
  46. # Virtual cards are structured, compound cards that are not stored in the database. You
  47. # can create virtual cards with structure rules.
  48. #
  49. # Some cards with hard-coded content will also override the #virtual? method. This
  50. # is established practice, but it is NOT advisable to override any of the other
  51. # state methods.
  52. #
  53. # @return [True/False]
  54. 1 def virtual?
  55. 525 if @virtual.nil?
  56. 244 @virtual = real? || name.simple? ? false : structure.present?
  57. end
  58. 525 @virtual
  59. end
  60. # @return [True/False]
  61. 1 def unknown?
  62. 63 !known?
  63. end
  64. # @return [True/False]
  65. 1 def known?
  66. 1395 real? || virtual?
  67. end
  68. # @return [True/False]
  69. 1 def new?
  70. 85638 new_record? || # not yet in db (from ActiveRecord)
  71. !@from_trash.nil? # in process of restoration from trash
  72. end
  73. 1 alias new_card? new?
  74. 1 alias unreal? new?
  75. # has not been edited directly by human users. bleep blorp.
  76. 1 def pristine?
  77. new_card? || !user_changes?
  78. end
  79. 1 def user_changes?
  80. actions.joins(:act).where("card_acts.actor_id != ?", WagnBotID).exists?
  81. end
  82. end;end;end;end;
  83. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/states.rb ~~

card/tmpsets/set/mod003-core/all/subcards.rb

73.13% lines covered

67 relevant lines. 49 lines covered and 18 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Subcards)
  4. #
  5. 1 module Subcards;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/subcards.rb"; end
  8. 1 def field tag, opts={}
  9. 2 Card.fetch name.field(tag), opts
  10. end
  11. 1 def subcard card_name
  12. subcards.card card_name
  13. end
  14. 1 def subfield field_name
  15. 6 subcards.field field_name
  16. end
  17. 1 def field? tag
  18. 2 field(tag) || subfield(tag)
  19. end
  20. 1 def subcards
  21. 4540 @subcards ||= Card::Subcards.new self
  22. end
  23. 1 def subcards?
  24. 2 subcards.present?
  25. end
  26. 1 def expire_subcards
  27. subcards.clear
  28. end
  29. # phase_method :attach_subcard, before: :store do |name_or_card, args=nil|
  30. # TODO: handle differently in different stages
  31. 1 def add_subcard name_or_card, args={}
  32. 182 subcards.add name_or_card, args
  33. end
  34. 1 alias_method :attach_subcard, :add_subcard
  35. 1 def add_subcard! name_or_card, args={}
  36. subcard = subcards.add name_or_card, args
  37. subcard.director.reset_stage
  38. subcard
  39. end
  40. 1 alias_method :attach_subcard!, :add_subcard!
  41. # phase_method :attach_subfield, before: :approve do |name_or_card, args=nil|
  42. 1 def attach_subfield name_or_card, args={}
  43. 8 subcards.add_field name_or_card, args
  44. end
  45. 1 alias_method :add_subfield, :attach_subfield
  46. 1 def attach_subfield! name_or_card, args={}
  47. subcard = subcards.add_field name_or_card, args
  48. subcard.director.reset_stage
  49. subcard
  50. end
  51. 1 def detach_subcard name_or_card
  52. subcards.remove name_or_card
  53. end
  54. 1 alias_method :remove_subcard, :detach_subcard
  55. 1 def detach_subfield name_or_card
  56. subcards.remove_field name_or_card
  57. end
  58. 1 alias_method :remove_subfield, :detach_subfield
  59. 1 def clear_subcards
  60. subcards.clear
  61. end
  62. # ensures subfield is present
  63. # does NOT override subfield content if already present
  64. 1 def ensure_subfield field_name, args={}
  65. if subfield_present? field_name
  66. subfield field_name
  67. else
  68. add_subfield field_name, args
  69. end
  70. end
  71. 1 def subfield_present? field_name
  72. subfield(field_name)&.content&.present?
  73. end
  74. 1 def deep_clear_subcards
  75. subcards.deep_clear
  76. end
  77. 1 def handle_subcard_errors
  78. 3528 subcards.each do |subcard|
  79. 1357 subcard.errors.each do |field, err|
  80. 4 subcard_error subcard, field, err
  81. end
  82. 1357 subcard.errors.clear
  83. end
  84. end
  85. 1 def subcard_error subcard, field, err
  86. 4 err = "#{field} #{err}" unless %i[content abort].member? field
  87. 4 errors.add subcard.name.from(name), err
  88. end
  89. 1 event :reject_empty_subcards, :prepare_to_validate do
  90. 332 subcards.each_with_key do |subcard, key|
  91. 42 next unless subcard.new? && subcard.unfilled?
  92. remove_subcard(key)
  93. director.subdirectors.delete(subcard)
  94. end
  95. end
  96. # check when deleting field that left has not also been deleted
  97. 1 def trashed_left?
  98. 1 l = left
  99. 1 !l || l.trash
  100. end
  101. # check when renaming field that it is not actually the same field
  102. # (eg on a renamed trunk)
  103. 1 def same_field?
  104. 3 (left_id == left_id_before_act) && (right_id == right_id_before_act)
  105. end
  106. end;end;end;end;
  107. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/subcards.rb ~~

card/tmpsets/set/mod003-core/all/tabs.rb

40.0% lines covered

30 relevant lines. 12 lines covered and 18 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Tabs)
  4. #
  5. 1 module Tabs;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/tabs.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :tabs do
  10. construct_tabs "tabs"
  11. end
  12. 1 def construct_tabs tab_type
  13. tabs = { active: {}, paths: {} }
  14. voo.items[:view] ||= :content
  15. card.each_item_name_with_options(_render_raw) do |name, options|
  16. construct_tab tabs, name, options
  17. end
  18. tabs tabs[:paths], tabs[:active][:name], tab_type: tab_type, load: :lazy do
  19. tabs[:active][:content]
  20. end
  21. end
  22. 1 def construct_tab tabs, name, explicit_options
  23. tab_options = item_view_options explicit_options
  24. tabs[:paths][name] = {
  25. title: nest(name, view: :title, title: tab_options[:title]),
  26. path: nest_path(name, tab_options).html_safe
  27. }
  28. return unless tabs[:active].empty?
  29. tabs[:active] = { name: name, content: nest(name, tab_options) }
  30. end
  31. # def tab_title title, name
  32. # return name unless title
  33. # name.to_name.title title, @context_names
  34. # end
  35. 1 view :pills do
  36. construct_tabs "pills"
  37. end
  38. 1 view :tabs_static do
  39. construct_static_tabs "tabs"
  40. end
  41. 1 view :pills_static do
  42. construct_static_tabs "pills"
  43. end
  44. 1 def construct_static_tabs tab_type
  45. tabs = {}
  46. card.item_cards.each do |item|
  47. tabs[item.name] = nest item, item_view_options(args)
  48. end
  49. tabs tabs, nil, tab_type: tab_type
  50. end
  51. end
  52. end;end;end;end;
  53. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/tabs.rb ~~

card/tmpsets/set/mod003-core/all/templating.rb

92.5% lines covered

40 relevant lines. 37 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Templating)
  4. #
  5. 1 module Templating;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/templating.rb"; end
  8. 1 def is_template?
  9. return @is_template unless @is_template.nil?
  10. @is_template = name.trait_name? :structure, :default
  11. end
  12. 1 def is_structure?
  13. 1223 return @is_structure unless @is_structure.nil?
  14. 543 @is_structure = name.trait_name? :structure
  15. end
  16. 1 def template
  17. # currently applicable templating card.
  18. # note that a *default template is never returned for an existing card.
  19. 5216 @template ||= begin
  20. 3312 @virtual = false
  21. 3312 if new_card?
  22. 926 new_card_template
  23. else
  24. 2386 structure_rule_card
  25. end
  26. end
  27. end
  28. 1 def default_type_id
  29. Card.default_type_id
  30. end
  31. 1 def new_card_template
  32. 926 default = rule_card :default, skip_modules: true
  33. 926 dup_card = dup
  34. 926 dup_card.type_id = default&.type_id || default_type_id
  35. 926 if (structure = dup_card.structure_rule_card)
  36. 142 @virtual = true if junction?
  37. 142 self.type_id = structure.type_id if assign_type_to?(structure)
  38. 142 structure
  39. else
  40. 784 default
  41. end
  42. end
  43. 1 def assign_type_to? structure
  44. 142 return if type_id == structure.type_id
  45. 104 structure.assigns_type?
  46. end
  47. 1 def assigns_type?
  48. # needed because not all *structure templates govern the type of set members
  49. # for example, X+*type+*structure governs all cards of type X,
  50. # but the content rule does not (in fact cannot) have the type X.
  51. 119 pattern_code = Card.quick_fetch(name.trunk_name.tag_name)&.codename
  52. 119 return unless pattern_code && (set_class = Set::Pattern.find pattern_code)
  53. 119 set_class.assigns_type
  54. end
  55. 1 def structure
  56. 3277 return unless template && template.is_structure?
  57. 109 template
  58. end
  59. 1 def structure_rule_card
  60. 3312 return unless (card = rule_card :structure, skip_modules: true)
  61. 156 card.db_content&.strip == "_self" ? nil : card
  62. end
  63. end;end;end;end;
  64. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/templating.rb ~~

card/tmpsets/set/mod003-core/all/trash.rb

63.77% lines covered

69 relevant lines. 44 lines covered and 25 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Trash)
  4. #
  5. 1 module Trash;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/trash.rb"; end
  8. 1 Self::Admin.add_to_basket(
  9. :tasks,
  10. name: :empty_trash,
  11. irreversible: true,
  12. execute_policy: -> { Card.empty_trash },
  13. stats: {
  14. title: "trashed cards",
  15. count: -> { Card.where(trash: true) },
  16. link_text: "empty trash",
  17. task: "empty_trash"
  18. }
  19. )
  20. 1 module ClassMethods
  21. 1 def empty_trash
  22. Card.delete_trashed_files
  23. Card.where(trash: true).in_batches.update_all(left_id: nil, right_id: nil)
  24. Card.where(trash: true).in_batches.delete_all
  25. Card::Action.delete_cardless
  26. Card::Change.delete_actionless
  27. Card::Act.delete_actionless
  28. Card::Reference.unmap_if_referee_missing
  29. Card::Reference.delete_if_referer_missing
  30. end
  31. # deletes any file not associated with a real card.
  32. 1 def delete_trashed_files
  33. dir = Cardio.paths["files"].existent.first
  34. # TODO: handle cloud files
  35. return unless dir
  36. trashed_card_ids = all_trashed_card_ids
  37. file_ids = all_file_ids
  38. file_ids.each do |file_id|
  39. next unless trashed_card_ids.member?(file_id)
  40. raise Card::Error, tr(:exception_almost_deleted) if Card.exists?(file_id)
  41. ::FileUtils.rm_rf "#{dir}/#{file_id}", secure: true
  42. end
  43. end
  44. 1 def all_file_ids
  45. dir = Card.paths["files"].existent.first
  46. Dir.entries(dir)[2..-1].map(&:to_i)
  47. end
  48. 1 def all_trashed_card_ids
  49. trashed_card_sql = %( select id from cards where trash is true )
  50. sql_results = Card.connection.select_all(trashed_card_sql)
  51. sql_results.map(&:values).flatten.map(&:to_i)
  52. end
  53. end
  54. 1 def delete args={}
  55. 8 add_to_trash args do |delete_args|
  56. 8 update delete_args
  57. end
  58. end
  59. 1 def delete! args={}
  60. 19 add_to_trash args do |delete_args|
  61. 19 update! delete_args
  62. end
  63. end
  64. 1 def add_to_trash args
  65. 27 return if new_card?
  66. 27 yield args.merge trash: true
  67. end
  68. 1 event :manage_trash, :prepare_to_store, on: :create do
  69. 190 pull_from_trash!
  70. 190 self.trash = false
  71. 190 true
  72. end
  73. 1 def pull_from_trash!
  74. 190 return unless (id = Card::Lexicon.id key) # name is already known
  75. 11 return unless (trashed_card = Card.where(id: id).take)&.trash
  76. # confirm name is actually in trash
  77. 11 db_attributes["id"] = trashed_card.db_attributes["id"]
  78. # id_in_database returns existing card id
  79. 11 @from_trash = true
  80. 11 @new_record = false
  81. end
  82. 1 def db_attributes
  83. 22 send(:mutations_from_database).send :attributes
  84. end
  85. 1 event :validate_delete, :validate, on: :delete do
  86. 78 unless codename.blank?
  87. errors.add :delete, tr(:error_system_card, name: name, codename: codename)
  88. end
  89. undeletable_all_rules_tags =
  90. 78 %w[default style layout create read update delete]
  91. # FIXME: HACK! should be configured in the rule
  92. 78 if junction? && left&.codename == :all &&
  93. undeletable_all_rules_tags.member?(right.codename.to_s)
  94. errors.add :delete, tr(:error_indestructible, name: name)
  95. end
  96. 78 errors.add :delete, tr(:error_user_edits, name: name) if account && has_edits?
  97. end
  98. 1 event :validate_delete_children, after: :validate_delete, on: :delete do
  99. 78 return if errors.any?
  100. 77 each_child do |child|
  101. 52 next unless child
  102. # prevents errors in cases where a child is deleted prior to this point
  103. # and thus is not returned by the fetch in #children
  104. 52 delete_as_subcard child
  105. # next if child.valid?
  106. # child.errors.each do |field, message|
  107. # errors.add field, "can't delete #{child.name}: #{message}"
  108. # end
  109. end
  110. end
  111. 1 def delete_as_subcard subcard
  112. 52 subcard.trash = true
  113. 52 add_subcard subcard
  114. end
  115. end;end;end;end;
  116. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/trash.rb ~~

card/tmpsets/set/mod003-core/all/type.rb

88.24% lines covered

34 relevant lines. 30 lines covered and 4 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Type)
  4. #
  5. 1 module Type;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/type.rb"; end
  8. 1 module ClassMethods
  9. 1 def default_type_id
  10. 3 @@default_type_id ||= Card[:all].fetch(:default, skip_modules: true).type_id
  11. end
  12. end
  13. 1 def type_card
  14. 6270 return if type_id.nil?
  15. 6270 Card.quick_fetch type_id.to_i
  16. end
  17. 1 def type_code
  18. 427 Card::Codename[type_id.to_i]
  19. end
  20. 1 def type_name
  21. 6257 type_card.try :name
  22. end
  23. 1 alias_method :type, :type_name
  24. 1 def type_name_or_default
  25. 7 type_card.try(:name) || Card.quick_fetch(Card.default_type_id).name
  26. end
  27. 1 def type_cardname
  28. type_card.try :name
  29. end
  30. 1 def type= type_name
  31. self.type_id = Card.fetch_id type_name
  32. end
  33. 1 def type_id= card_or_id
  34. 2803 write_card_or_id :type_id, card_or_id
  35. end
  36. 1 def type_id_from_template
  37. 524 return unless name && (t = template)
  38. 524 reset_patterns # still necessary even with new template handling?
  39. 524 self.type_id = t.type_id
  40. end
  41. 1 event :validate_type_change, :validate, on: :update, changed: :type_id do
  42. 1 if (c = dup) && c.action == :create && !c.valid?
  43. errors.add :type, tr(
  44. :error_cant_change_errors,
  45. name: name, type_id: type_id,
  46. error_messages: c.errors.full_messages
  47. )
  48. end
  49. end
  50. 1 event :validate_type, :validate, changed: :type_id, on: :save do
  51. 197 errors.add :type, tr(:error_no_such_type) unless type_name
  52. 197 if (rt = structure) && rt.assigns_type? && type_id != rt.type_id
  53. errors.add :type, tr(:error_hard_templated, name: name, type_name: rt.type_name)
  54. end
  55. end
  56. end;end;end;end;
  57. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/type.rb ~~

card/tmpsets/set/mod003-core/all/update_read_rules.rb

100.0% lines covered

9 relevant lines. 9 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (UpdateReadRules)
  4. #
  5. 1 module UpdateReadRules;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/update_read_rules.rb"; end
  8. # FIXME: the following don't really belong here, but they have to come after
  9. # the reference stuff. we need to organize a bit!
  10. 1 event :update_rule_cache, :finalize, when: :is_rule? do
  11. 10 Card::Rule.clear_rule_cache
  12. end
  13. 1 event :expire_related, :finalize do
  14. 318 reset_patterns
  15. 318 structuree_names.each { |name| Director.expirees << name } if is_structure?
  16. end
  17. end;end;end;end;
  18. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/update_read_rules.rb ~~

card/tmpsets/set/mod003-core/all/utils.rb

35.19% lines covered

54 relevant lines. 19 lines covered and 35 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Utils)
  4. #
  5. 1 module Utils;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/core/set/all/utils.rb"; end
  8. 1 module ClassMethods
  9. 1 def merge_list attribs, opts={}
  10. unmerged = []
  11. attribs.each do |row|
  12. if merge row["name"], row, opts
  13. Rails.logger.info "merged #{row['name']}"
  14. else
  15. unmerged.push row
  16. end
  17. end
  18. if unmerged.empty?
  19. Rails.logger.info "successfully merged all!"
  20. else
  21. unmerged_json = JSON.pretty_generate unmerged
  22. report_unmerged_json unmerged_json, opts[:output_file]
  23. end
  24. unmerged
  25. end
  26. 1 def report_unmerged_json unmerged_json, output_file
  27. if output_file
  28. ::File.open output_file, "w" do |f|
  29. f.write unmerged_json
  30. end
  31. else
  32. Rails.logger.info "failed to merge:\n\n#{unmerged_json}"
  33. end
  34. end
  35. 1 def merge name, attribs={}, opts={}
  36. # puts "merging #{name}"
  37. card = fetch name, new: {}
  38. return unless mergeable? card, opts[:pristine]
  39. resolve_file_attributes! attribs
  40. card.safe_update! attribs
  41. end
  42. 1 private
  43. 1 def resolve_file_attributes! attribs
  44. %i[image file].each do |attach|
  45. next unless attribs[attach] && attribs[attach].is_a?(String)
  46. attribs[attach] = ::File.open(attribs[attach])
  47. end
  48. end
  49. 1 def mergeable? card, pristine_only
  50. return true unless pristine_only
  51. !card.pristine?
  52. end
  53. end
  54. # separate name and other attributes
  55. 1 def safe_update! attribs
  56. separate_name_update! attribs.delete("name") unless new?
  57. update! attribs if attribs.present?
  58. end
  59. 1 def separate_name_update! new_name
  60. return if new_name.to_s == name.to_s
  61. update! name: new_name
  62. end
  63. # rubocop:disable Style/GlobalVars
  64. 1 def measure desc
  65. $times ||= {}
  66. res = nil
  67. t = Benchmark.measure do
  68. res = yield
  69. end
  70. $times[desc] = $times.key?(desc) ? t + $times[desc] : t
  71. puts "#{desc}: #{t}".red
  72. res
  73. end
  74. # rubocop:enable Style/GlobalVars
  75. 1 def mod_root modname
  76. 36 if (spec = Gem::Specification.find_by_name "card-mod-#{modname}")
  77. 36 spec.full_gem_path
  78. else
  79. "#{Cardio.gem_root}/mod/#{modname}"
  80. end
  81. end
  82. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  83. 1 delegate :measure, to: :card
  84. end
  85. end;end;end;end;
  86. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set/all/utils.rb ~~

card/tmpsets/set/mod004-card-mod-format/all/all_css.rb

54.17% lines covered

24 relevant lines. 13 lines covered and 11 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (AllCss)
  4. #
  5. 1 module AllCss;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-format/set/all/all_css.rb"; end
  8. 2 module CssFormat; module_parent.send :register_set_format, Card::Format::CssFormat, self; extend Card::Set::AbstractFormat
  9. 1 def default_nest_view
  10. :raw
  11. end
  12. 1 def show view, args
  13. view ||= :content
  14. render! view, args
  15. end
  16. 1 view :titled do
  17. major_comment(%( Style Card: \\"#{card.name}\\" )) + _render_core
  18. end
  19. 1 view :content do
  20. _render_core
  21. end
  22. 1 view :unknown do
  23. major_comment "MISSING Style Card: #{card.name}"
  24. end
  25. 1 view :import do
  26. _render_core
  27. end
  28. 1 view :url, perms: :none do
  29. path mark: card.name, format: :css
  30. end
  31. 1 def major_comment comment, char="-"
  32. edge = %(/* #{char * (comment.length + 4)} */)
  33. main = %(/* #{char} #{comment} #{char} */)
  34. "#{edge}\n#{main}\n#{edge}\n\n"
  35. end
  36. end
  37. end;end;end;end;
  38. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-format/set/all/all_css.rb ~~

card/tmpsets/set/mod004-card-mod-format/all/all_csv.rb

38.89% lines covered

54 relevant lines. 21 lines covered and 33 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (AllCsv)
  4. #
  5. 1 module AllCsv;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-format/set/all/all_csv.rb"; end
  8. 1 require "csv"
  9. 2 module CsvFormat; module_parent.send :register_set_format, Card::Format::CsvFormat, self; extend Card::Set::AbstractFormat
  10. 1 def default_nest_view
  11. :core
  12. end
  13. 1 def default_item_view
  14. depth.zero? ? :csv_row : :name
  15. end
  16. 1 view :core do
  17. if (item_view_options[:view] == :name_with_fields) && focal?
  18. title_row("item name") + name_with_field_rows
  19. else
  20. super()
  21. end
  22. end
  23. 1 view :csv_row do
  24. array = _render_raw.scan(/\{\{[^\}]*\}\}/).map do |inc|
  25. process_content(inc).strip
  26. end
  27. CSV.generate_line(array).strip
  28. # strip is because search already joins with newlines
  29. end
  30. 1 view :unknown do
  31. ""
  32. end
  33. 1 view :name_with_fields do
  34. CSV.generate_line name_with_fields_row
  35. end
  36. 1 def name_with_fields_row
  37. nested_field_names.each_with_object([card.name]) do |field_name, row|
  38. row << nest(field_name)
  39. end
  40. end
  41. 1 def name_with_field_rows
  42. return [] unless row_card_names.present?
  43. row_card_names.map do |item_name|
  44. CSV.generate_line row_from_field_names(item_name, columns)
  45. end.join
  46. end
  47. 1 def row_card_names
  48. @row_cards ||= card.item_names
  49. end
  50. 1 def columns
  51. csv_structure_card.format.nested_field_names.map(&:tag)
  52. end
  53. 1 def csv_structure_card
  54. card.rule_card(:csv_structure) || Card.fetch(row_card_names.first)
  55. end
  56. 1 def row_from_field_names parent_name, field_names, view=:core
  57. field_names.each_with_object([parent_name]) do |field, row|
  58. row << nest([parent_name, field], view: view)
  59. end
  60. end
  61. 1 def title_row extra_titles=nil
  62. titles = column_titles extra_titles
  63. return "" unless titles.present?
  64. CSV.generate_line titles.map(&:upcase)
  65. end
  66. 1 def column_titles extra_titles=nil
  67. res = Array extra_titles
  68. card1 = Card.fetch card.item_names(limit: 1).first
  69. card1.nest_chunks.each do |chunk|
  70. res << column_title(chunk.options)
  71. end
  72. res.compact
  73. end
  74. 1 def column_title opts
  75. if opts[:title]
  76. opts[:title]
  77. elsif %w[name link].member? opts[:view]
  78. opts[:view]
  79. else
  80. opts[:nest_name].to_name.tag
  81. end
  82. end
  83. end
  84. end;end;end;end;
  85. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-format/set/all/all_csv.rb ~~

card/tmpsets/set/mod004-card-mod-format/all/all_js.rb

77.78% lines covered

9 relevant lines. 7 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (AllJs)
  4. #
  5. 1 module AllJs;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-format/set/all/all_js.rb"; end
  8. 2 module JsFormat; module_parent.send :register_set_format, Card::Format::JsFormat, self; extend Card::Set::AbstractFormat
  9. 1 def default_item_view
  10. :core
  11. end
  12. 1 view :source do
  13. path format: :js
  14. end
  15. end
  16. end;end;end;end;
  17. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-format/set/all/all_js.rb ~~

card/tmpsets/set/mod004-card-mod-format/all/base.rb

76.39% lines covered

72 relevant lines. 55 lines covered and 17 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Base)
  4. #
  5. 1 module Base;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-format/set/all/base.rb"; end
  8. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  9. 1 def show view, args
  10. 3 view ||= :core
  11. 3 render! view, args.merge(main_nest_options)
  12. end
  13. # NAME VIEWS
  14. 1 view :name, compact: true, perms: :none do
  15. 8 name_variant safe_name
  16. end
  17. 1 def safe_name
  18. 31 card&.name
  19. end
  20. 1 def name_variant name
  21. 163 voo.variant ? name.to_name.vary(voo.variant) : name
  22. end
  23. 1 view(:key, compact: true, perms: :none) { card.key }
  24. 5 view(:linkname, compact: true, perms: :none) { card.name.url_key }
  25. 5 view(:url, compact: true, perms: :none) { card_url _render_linkname }
  26. 1 view :url_link, compact: true, perms: :none do
  27. link_to_resource card_url(_render_linkname)
  28. end
  29. 1 view :link, compact: true, perms: :none do
  30. 14 link_view
  31. end
  32. 1 view :nav_link, compact: true, perms: :none do
  33. link_view class: "nav-link"
  34. end
  35. 1 def link_view opts={}
  36. 37 opts[:known] = card.known?
  37. 37 specify_type_in_link! opts
  38. 37 link_to_card card.name, _render_title, opts
  39. end
  40. 1 def specify_type_in_link! opts
  41. 37 return if opts[:known] || !voo.type
  42. opts[:path] = { card: { type: voo.type } }
  43. end
  44. 1 view(:codename, compact: true) { card.codename.to_s }
  45. 1 view(:id, compact: true) { card.id }
  46. 1 view(:type, compact: true) { card.type_name }
  47. # DATE VIEWS
  48. 1 view(:created_at, compact: true) { date_view card.created_at }
  49. 1 view(:updated_at, compact: true) { date_view card.updated_at }
  50. 1 view(:acted_at, compact: true) { date_view card.acted_at }
  51. 1 def date_view date
  52. if voo.variant
  53. date.strftime voo.variant
  54. else
  55. time_ago_in_words date
  56. end
  57. end
  58. # CONTENT VIEWS
  59. 1 view :raw do
  60. 251 structure_card&.content || _render_blank
  61. end
  62. 1 def structure_card
  63. 251 return nil if voo.structure == true
  64. 251 voo.structure ? Card[voo.structure] : card
  65. end
  66. 1 view :core, compact: true do
  67. 171 process_content _render_raw
  68. end
  69. 1 view :content do
  70. _render_core
  71. end
  72. 1 view :open_content do
  73. 2 _render_core
  74. end
  75. 1 view :one_line_content, compact: true do
  76. with_nest_mode :compact do
  77. Card::Content.smart_truncate _render_core
  78. end
  79. end
  80. 1 view :labeled_content, unknown: :mini_unknown do
  81. render_core
  82. end
  83. 1 view :titled_content, unknown: :blank do
  84. render_core
  85. end
  86. 1 view :blank, compact: true, perms: :none do
  87. 56 ""
  88. end
  89. # note: content and open_content may look like they should be aliased to
  90. # core, but it's important that they render core explicitly so that core view
  91. # overrides work. the titled and labeled views below, however, are not
  92. # intended for frequent override, so this shortcut is fine.
  93. # NAME + CONTENT VIEWS
  94. 1 view :titled do
  95. "#{card.name}\n\n#{_render_core}"
  96. end
  97. 1 view :open, :titled
  98. 1 view :labeled do
  99. "#{card.name}: #{_render_labeled_content}"
  100. end
  101. 1 view :closed, :labeled
  102. # SPECIAL VIEWS
  103. 1 view :array, cache: :never do
  104. card.item_cards(limit: 0).map do |item_card|
  105. subformat(item_card)._render_core
  106. end.inspect
  107. end
  108. # DEPRECATED
  109. 1 view :naked do
  110. Rails.logger.info "DEPRECATED: naked view (used with #{card.name} card)"
  111. render_core
  112. end
  113. end
  114. end;end;end;end;
  115. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-format/set/all/base.rb ~~

card/tmpsets/set/mod004-card-mod-format/all/file.rb

77.78% lines covered

9 relevant lines. 7 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (File)
  4. #
  5. 1 module File;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-format/set/all/file.rb"; end
  8. 2 module FileFormat; module_parent.send :register_set_format, Card::Format::FileFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :core do
  10. "File rendering of this card not yet supported"
  11. end
  12. 1 view :style do
  13. nil
  14. end
  15. end
  16. end;end;end;end;
  17. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-format/set/all/file.rb ~~

card/tmpsets/set/mod004-card-mod-format/all/head.rb

93.42% lines covered

76 relevant lines. 71 lines covered and 5 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Head)
  4. #
  5. 1 module Head;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-format/set/all/head.rb"; end
  8. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  9. 1 view :page_title, unknown: true, perms: :none do
  10. 23 title_parts = [Card::Rule.global_setting(:title)]
  11. 23 title_parts.unshift safe_name if card.name.present?
  12. 23 title_parts.join " - "
  13. end
  14. end
  15. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  16. # add tuples containing a
  17. # - the codename of a card with javascript config (usually in json format)
  18. # - the name of a javascript method that handles the config
  19. 1 basket :mod_js_config
  20. 1 view :head, unknown: true, perms: :none do
  21. 276 views_in_head.map { |viewname| render viewname }.flatten.compact.join "\n"
  22. end
  23. 1 def views_in_head
  24. 23 %i[meta_tags page_title_tag favicon_tag head_stylesheet
  25. decko_script_variables head_javascript html5shiv_tag
  26. script_config_and_initiation
  27. universal_edit_button rss_links]
  28. end
  29. # FIXME: tags not working with `template: :haml`
  30. 1 view :meta_tags, unknown: true, perms: :none do
  31. 23 haml :meta_tags
  32. end
  33. 1 view :html5shiv_tag, unknown: true, perms: :none do
  34. 23 nest :script_html5shiv_printshiv, view: :script_tag
  35. end
  36. 1 view :page_title_tag, unknown: true, perms: :none do
  37. 46 content_tag(:title) { render :page_title }
  38. end
  39. 1 view :favicon_tag, unknown: true, perms: :none do
  40. 23 nest :favicon, view: :link_tag
  41. end
  42. 1 view :universal_edit_button, unknown: true, denial: :blank, perms: :update do
  43. 15 return if card.new?
  44. 5 tag "link", rel: "alternate", type: "application/x-wiki",
  45. title: "Edit this page!", href: path(view: :edit)
  46. end
  47. # these should render a view of the rule card
  48. # it would then be safe to cache if combined with param handling
  49. # (but note that machine clearing would need to reset card cache...)
  50. 1 view :head_stylesheet, unknown: true, cache: :never, perms: :none do
  51. 23 return unless (href = head_stylesheet_path)
  52. 23 tag "link", href: href, media: "all", rel: "stylesheet", type: "text/css"
  53. end
  54. 1 view :head_javascript, unknown: true, cache: :never, perms: :none do
  55. 23 Array.wrap(head_javascript_paths).map do |path|
  56. 23 javascript_include_tag path
  57. end
  58. end
  59. 1 view :decko_script_variables, unknown: true, cache: :never, perms: :none do
  60. 23 string = ""
  61. 23 decko_script_variables.each do |k, v|
  62. 92 string += "#{k}=#{script_variable_to_js v};\n"
  63. end
  64. 46 javascript_tag { string }
  65. end
  66. 1 def decko_script_variables
  67. {
  68. 23 "window.decko": { rootUrl: card_url("") },
  69. "decko.doubleClick": Card.config.double_click,
  70. "decko.cssPath": head_stylesheet_path,
  71. 23 "decko.currentUserId": (Auth.current_id if Auth.signed_in?)
  72. }
  73. end
  74. 1 def script_variable_to_js value
  75. 115 if value.is_a? Hash
  76. 23 string = "{"
  77. 46 value.each { |k, v| string += "#{k}:#{script_variable_to_js v}" }
  78. 23 string + "}"
  79. else
  80. 92 "'#{value}'"
  81. end
  82. end
  83. 1 def param_or_rule_card setting
  84. 69 if params[setting]
  85. Card[params[setting]]
  86. else
  87. 69 root.card.rule_card setting
  88. end
  89. end
  90. 1 def debug_or_machine_path setting, &block
  91. 69 return unless (asset_card = param_or_rule_card setting)
  92. 69 debug_path(setting, asset_card, &block) || asset_card.machine_output_url
  93. end
  94. 1 def debug_path setting, asset_card
  95. 69 return unless params[:debug] == setting.to_s
  96. yield asset_card
  97. end
  98. 1 def head_stylesheet_path
  99. 46 debug_or_machine_path :style do |style_card|
  100. path mark: style_card.name, item: :import, format: :css
  101. end
  102. end
  103. 1 def head_javascript_paths
  104. 23 debug_or_machine_path :script do |script_card|
  105. script_card.item_cards.map do |script|
  106. script.format(:js).render :source
  107. end
  108. end
  109. end
  110. 1 view :script_config_and_initiation, unknown: true, perms: :none do
  111. 23 javascript_tag do
  112. 23 (mod_js_configs << trigger_slot_ready).join "\n\n"
  113. end
  114. end
  115. 1 def mod_js_configs
  116. 23 mod_js_config.map do |codename, js_decko_function|
  117. 92 config_json = escape_javascript Card::Rule.global_setting(codename)
  118. 92 "decko.#{js_decko_function}('#{config_json}')"
  119. end
  120. end
  121. 1 def trigger_slot_ready
  122. 23 "$('document').ready(function() { $('.card-slot').trigger('slotReady'); })"
  123. end
  124. # TODO: move to rss mod
  125. 1 view :rss_links, unknown: true, perms: :none do
  126. 23 render :rss_link_tag if rss_link?
  127. end
  128. 1 def rss_link?
  129. 23 Card.config.rss_enabled && respond_to?(:rss_link_tag)
  130. end
  131. end
  132. end;end;end;end;
  133. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-format/set/all/head.rb ~~

card/tmpsets/set/mod004-card-mod-format/all/json.rb

41.1% lines covered

73 relevant lines. 30 lines covered and 43 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Json)
  4. #
  5. 1 module Json;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-format/set/all/json.rb"; end
  8. 2 module JsonFormat; module_parent.send :register_set_format, Card::Format::JsonFormat, self; extend Card::Set::AbstractFormat
  9. # because card.item_cards returns "[[#{self}]]"
  10. 1 def item_cards
  11. nested_cards
  12. end
  13. 1 def default_nest_view
  14. :atom
  15. end
  16. 1 def default_item_view
  17. params[:item] || :name
  18. end
  19. 1 def max_depth
  20. params[:max_depth].present? ? params[:max_depth].to_i : 1
  21. end
  22. # TODO: support layouts in json
  23. # eg layout=stamp gives you the metadata currently in "page" view
  24. # and layout=none gives you ONLY the requested view (default atom)
  25. 1 def show view, args
  26. view ||= :molecule
  27. raw = render! view, args
  28. raw.is_a?(String) ? raw : stringify(raw)
  29. end
  30. 1 def stringify raw
  31. method = params[:compress] ? :generate : :pretty_generate
  32. JSON.send method, raw
  33. end
  34. 1 view :status, unknown: true, perms: :none do
  35. status = card.state
  36. hash = { key: card.key,
  37. url_key: card.name.url_key,
  38. status: status }
  39. hash[:id] = card.id if status == :real
  40. hash
  41. end
  42. # NOCACHE because of timestamp
  43. 1 view :page, cache: :never do
  44. { url: request_url,
  45. timestamp: Time.now.to_s,
  46. card: _render_atom }
  47. end
  48. 1 def request_url
  49. req = controller.request
  50. req ? req.original_url : path
  51. end
  52. 1 view :core, unknown: true do
  53. card.known? ? render_content : nil
  54. end
  55. 1 view :content do
  56. card.content
  57. end
  58. 1 view :nucleus do
  59. nucleus
  60. end
  61. # TODO: add simple values for fields
  62. 1 view :atom, unknown: true do
  63. atom
  64. end
  65. 1 view :molecule do
  66. molecule
  67. end
  68. # NOCACHE because sometimes item_cards is dynamic.
  69. # could be safely cached for non-dynamic lists
  70. 1 view :items, cache: :never do
  71. listing item_cards, view: :atom
  72. end
  73. 1 view :links do
  74. card.link_chunks.map do |chunk|
  75. if chunk.referee_name
  76. path mark: chunk.referee_name, format: :json
  77. else
  78. link_to_resource chunk.link_target
  79. end
  80. end
  81. end
  82. 1 view :ancestors do
  83. card.name.ancestors.map do |name|
  84. nest name, view: :nucleus
  85. end
  86. end
  87. # minimum needed to re-fetch card
  88. 1 view :cast do
  89. card.cast
  90. end
  91. ## DEPRECATED
  92. 1 view :marks do
  93. {
  94. id: card.id,
  95. name: card.name,
  96. key: card.key,
  97. url: path
  98. }
  99. end
  100. 1 view :essentials do
  101. if voo.show? :marks
  102. render_marks.merge(essentials)
  103. else
  104. essentials
  105. end
  106. end
  107. 1 def essentials
  108. return {} if card.structure
  109. { content: card.db_content }
  110. end
  111. # NOTE: moving these to methods prevents potential caching problems, because other
  112. # views manipulate their hashes.
  113. #
  114. 1 def nucleus
  115. h = { id: card.id,
  116. name: card.name,
  117. type: card.type_name,
  118. url: path(format: :json) }
  119. h[:codename] = card.codename if card.codename
  120. h
  121. end
  122. 1 def atom
  123. h = nucleus
  124. h[:content] = render_content if card.known? && !card.structure
  125. h
  126. end
  127. 1 def molecule
  128. atom.merge items: _render_items,
  129. links: _render_links,
  130. ancestors: _render_ancestors,
  131. html_url: path,
  132. type: nest(card.type_card, view: :nucleus)
  133. end
  134. end
  135. # TODO: perhaps this should be in a general "data" module.
  136. 1 def cast
  137. real? ? { id: id } : { name: name, type_id: type_id, content: db_content }
  138. end
  139. end;end;end;end;
  140. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-format/set/all/json.rb ~~

card/tmpsets/set/mod004-card-mod-format/all/rss.rb

45.83% lines covered

48 relevant lines. 22 lines covered and 26 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Rss)
  4. #
  5. 1 module Rss;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-format/set/all/rss.rb"; end
  8. 2 module RssFormat; module_parent.send :register_set_format, Card::Format::RssFormat, self; extend Card::Set::AbstractFormat
  9. 1 attr_accessor :xml
  10. 1 def initialize card, args
  11. super
  12. @xml = @parent ? @parent.xml : ::Builder::XmlMarkup.new
  13. end
  14. 1 def show view, args
  15. view ||= :feed
  16. render! view, args
  17. end
  18. # FIXME: integrate this with common XML features when it is added
  19. 1 view :feed, cache: :never do
  20. return "RSS feeds disabled" unless Cardio.config.rss_enabled
  21. begin
  22. @xml.instruct! :xml, version: "1.0", standalone: "yes"
  23. @xml.rss version: "2.0",
  24. "xmlns:content" => "http://purl.org/rss/1.0/modules/content/" do
  25. @xml.channel do
  26. @xml.title render_feed_title
  27. @xml.description render_feed_description
  28. @xml.link render_url
  29. render_feed_body
  30. end
  31. end
  32. rescue => e
  33. @xml.error "\n\nERROR rendering RSS: #{e.inspect}\n\n #{e.backtrace}"
  34. end
  35. end
  36. 1 def raw_feed_items
  37. [card]
  38. end
  39. 1 view :feed_body, cache: :never do
  40. raw_feed_items.each do |item|
  41. @xml.item do
  42. subformat(item).render! :feed_item
  43. end
  44. end
  45. end
  46. 1 view :feed_title do
  47. Card::Rule.global_setting(:title) + " : " + card.name.gsub(/^\*/, "")
  48. end
  49. 1 view :feed_item do
  50. @xml.title card.name
  51. add_name_context
  52. @xml.description render_feed_item_description
  53. @xml.pubDate pub_date
  54. @xml.link render_url
  55. @xml.guid render_url
  56. end
  57. 1 def pub_date
  58. (card.updated_at || Time.zone.now).to_s(:rfc822)
  59. # updated_at fails on virtual
  60. # cards, because not all to_s's take args (just actual dates)
  61. end
  62. 1 view :feed_item_description do
  63. render_open_content
  64. end
  65. 1 view(:feed_description) { "" }
  66. 1 view(:comment_box) { "" }
  67. 1 view(:menu) { "" }
  68. 1 view :open, :titled, mod: All::Base::Format
  69. 1 view :content, :core, mod: All::Base::Format
  70. 1 view :open_content, :core, mod: All::Base::Format
  71. 1 view :closed, :link, mod: All::Base::Format
  72. end
  73. end;end;end;end;
  74. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-format/set/all/rss.rb ~~

card/tmpsets/set/mod004-card-mod-format/all/text.rb

100.0% lines covered

7 relevant lines. 7 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Text)
  4. #
  5. 1 module Text;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-format/set/all/text.rb"; end
  8. 2 module TextFormat; module_parent.send :register_set_format, Card::Format::TextFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :core do
  10. 4 HTMLEntities.new.decode strip_tags(super()).to_s
  11. # need this string method to get out of html_safe mode
  12. end
  13. end
  14. end;end;end;end;
  15. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-format/set/all/text.rb ~~

card/tmpsets/set/mod004-card-mod-format/self/head.rb

91.67% lines covered

12 relevant lines. 11 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Head"
  4. #
  5. 1 module Head;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-format/set/self/head.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. # when *head is rendered in the main body of a page, we escape the HTML
  10. # otherwise (most typically in the head tag, of course), we render the
  11. # HTML unescaped
  12. 1 view :core, cache: :never do
  13. 23 escape_in_main do
  14. 23 nest root.card, view: :head
  15. # note that the head tag for each card is different
  16. # (different title, different style rules, etc)
  17. # so we don't cache the core of *head, but we _do_ cache some
  18. # views within each head (see all/head.rb)
  19. end
  20. end
  21. 1 view :input do
  22. "Content can't be edited."
  23. end
  24. 1 def escape_in_main
  25. 23 main? ? (h yield) : yield
  26. end
  27. end
  28. end;end;end;end;
  29. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-format/set/self/head.rb ~~

card/tmpsets/set/mod004-card-mod-format/type/html.rb

72.22% lines covered

18 relevant lines. 13 lines covered and 5 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Html" cards
  4. #
  5. 1 module Html;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-format/set/type/html.rb"; end
  8. 1 def clean_html?
  9. false
  10. end
  11. 1 def diff_args
  12. { diff_format: :raw }
  13. end
  14. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  15. 1 view :one_line_content do
  16. raw_one_line_content
  17. end
  18. 1 def chunk_list
  19. 115 :references
  20. end
  21. end
  22. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  23. 1 def input_type
  24. :ace_editor
  25. end
  26. 1 view :one_line_content, wrap: {} do
  27. raw_one_line_content
  28. end
  29. end
  30. end;end;end;end;
  31. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-format/set/type/html.rb ~~

card/tmpsets/set/mod004-card-mod-format/type/json.rb

70.83% lines covered

24 relevant lines. 17 lines covered and 7 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Json" cards
  4. #
  5. # include_set Abstract::Pointer
  6. 1 module Json;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-format/set/type/json.rb"; end
  9. 1 event :validate_json, :validate, on: :save, changed: :content do
  10. 10 check_json_syntax if content.present?
  11. end
  12. 1 def check_json_syntax
  13. 10 parse_content
  14. rescue JSON::ParserError => e
  15. errors.add tr(:invalid_json), e.message.sub(/^\d+: /, "").to_s
  16. end
  17. 1 def parse_content
  18. 10 JSON.parse content
  19. end
  20. 1 def item_names _args={}
  21. parse_content.keys.map(&:to_name)
  22. end
  23. 1 def item_values
  24. parse_content.values
  25. end
  26. 1 def item_value name
  27. parse_content[name]
  28. end
  29. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  30. 1 view :core do
  31. process_content ::CodeRay.scan(_render_raw, :json).div
  32. end
  33. 1 def input_type
  34. :ace_editor
  35. end
  36. 1 def ace_mode
  37. :json
  38. end
  39. end
  40. end;end;end;end;
  41. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-format/set/type/json.rb ~~

card/tmpsets/set/mod004-card-mod-format/type/plain_text.rb

77.78% lines covered

9 relevant lines. 7 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "PlainText" cards
  4. #
  5. 1 module PlainText;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-format/set/type/plain_text.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def input_type
  10. :text_area
  11. end
  12. 1 view :core do
  13. process_content CGI.escapeHTML(_render_raw)
  14. end
  15. end
  16. end;end;end;end;
  17. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-format/set/type/plain_text.rb ~~

card/tmpsets/set/mod005-pointer/abstract/00_paging_params.rb

85.0% lines covered

20 relevant lines. 17 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (PagingParams)
  4. #
  5. 1 module PagingParams;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/00_paging_params.rb"; end
  8. 1 MAX_ANONYMOUS_SEARCH_PARAM = 1000
  9. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  10. 1 def limit_param
  11. 1 @limit ||= contextual_param(:limit) || default_limit
  12. end
  13. 1 def offset_param
  14. 1 @offset ||= contextual_param(:offset) || 0
  15. end
  16. 1 def contextual_param param
  17. 2 env_search_param(param) || voo_search_param(param)
  18. end
  19. 1 def env_search_param param
  20. 2 return unless focal? && Env.params[param].present?
  21. legal_search_param! param, Env.params[param].to_i
  22. end
  23. 1 def legal_search_param! param, val
  24. return val if Card::Auth.signed_in? || val <= MAX_ANONYMOUS_SEARCH_PARAM
  25. raise Card::Error::PermissionDenied, "#{param} parameter exceeds maximum"
  26. end
  27. 1 def voo_search_param param
  28. 2 voo&.cql&.dig param
  29. end
  30. end
  31. end;end;end;end;
  32. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/00_paging_params.rb ~~

card/tmpsets/set/mod005-pointer/abstract/01_paging.rb

41.89% lines covered

74 relevant lines. 31 lines covered and 43 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (Paging)
  4. #
  5. 1 module Paging;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/01_paging.rb"; end
  8. 1 include_set Abstract::PagingParams
  9. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  10. 1 def limit
  11. limit_param
  12. end
  13. 1 def offset
  14. offset_param
  15. end
  16. 1 def search_with_params
  17. card.item_names
  18. end
  19. 1 def count_with_params
  20. card.item_names.count
  21. end
  22. 1 def total_pages
  23. return 1 if limit.zero?
  24. ((count_with_params - 1) / limit).to_i
  25. end
  26. 1 def current_page
  27. (offset / limit).to_i
  28. end
  29. # for override
  30. 1 def extra_paging_path_args
  31. {}
  32. end
  33. end
  34. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  35. 1 PAGE_LI_CLASS = { ellipses: "disabled", current: "active" }.freeze
  36. 1 def with_paging path_args={}
  37. with_paging_path_args path_args do
  38. output [yield(@paging_path_args), _render_paging]
  39. end
  40. end
  41. 1 view :paging, cache: :never do
  42. return "" unless paging_needed?
  43. <<-HTML
  44. <nav>
  45. <ul class="pagination paging">
  46. #{paging_links.join}
  47. </ul>
  48. </nav>
  49. HTML
  50. end
  51. 1 def paging_links
  52. PagingLinks.new(total_pages, current_page)
  53. .build do |text, page, status, options|
  54. page_link_li text, page, status, options
  55. end
  56. end
  57. # First page is 0 (not 1)
  58. 1 def page_link_li text, page, status, options={}
  59. wrap_with :li, class: page_link_li_class(status) do
  60. page_link text, page, options
  61. end
  62. end
  63. 1 def page_link_li_class status
  64. ["page-item", PAGE_LI_CLASS[status]].compact.join " "
  65. end
  66. 1 def page_link text, page, options
  67. return content_tag(:div, text.html_safe, class: "page-link") unless page
  68. options.merge! class: "card-paging-link slotter page-link",
  69. remote: true,
  70. path: page_link_path_args(page)
  71. link_to raw(text), options
  72. end
  73. 1 def with_paging_path_args args
  74. tmp = @paging_path_args
  75. @paging_path_args = paging_path_args args
  76. yield
  77. ensure
  78. @paging_path_args = tmp
  79. end
  80. 1 def paging_path_args local_args={}
  81. @paging_path_args ||= {}
  82. @paging_path_args.reverse_merge!(limit: limit, offset: offset)
  83. @paging_path_args.merge! extra_paging_path_args
  84. @paging_path_args.merge local_args
  85. end
  86. 1 def page_link_path_args page
  87. paging_path_args.merge offset: page * limit
  88. end
  89. 1 def paging_needed?
  90. return false if limit < 1
  91. return false if fewer_results_than_limit? # avoid extra count search
  92. # count search result instead
  93. limit < count_with_params
  94. end
  95. # clear we don't need paging even before running count query
  96. 1 def fewer_results_than_limit?
  97. return false unless offset.zero?
  98. limit > offset + search_with_params.length
  99. end
  100. end
  101. 2 module JsonFormat; module_parent.send :register_set_format, Card::Format::JsonFormat, self; extend Card::Set::AbstractFormat
  102. 1 def page_link_path_args page
  103. {
  104. limit: limit,
  105. offset: page * limit,
  106. item: default_item_view, # hack. need standard voo handling
  107. format: :json
  108. }.merge extra_paging_path_args
  109. end
  110. 1 view :paging_urls, cache: :never do
  111. return {} unless total_pages > 1
  112. { paging: paging_urls_hash }
  113. end
  114. 1 def paging_urls_hash
  115. hash = {}
  116. PagingLinks.new(total_pages, current_page)
  117. .build do |_text, page, status, _options|
  118. add_paging_url hash, page, status
  119. end
  120. hash
  121. end
  122. 1 def add_paging_url hash, page, status
  123. return unless page && status.in?(%i[next previous])
  124. hash[status] = path page_link_path_args(page)
  125. end
  126. end
  127. end;end;end;end;
  128. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/01_paging.rb ~~

card/tmpsets/set/mod005-pointer/abstract/01_paging/paging_links.rb

41.86% lines covered

43 relevant lines. 18 lines covered and 25 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (Paging)
  4. #
  5. #! no set module
  6. 1 module Paging;
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/01_paging/paging_links.rb"; end
  8. # render paging links
  9. 1 class PagingLinks
  10. 1 def initialize total_pages, current_page
  11. @total = total_pages
  12. @current = current_page
  13. end
  14. # @param window [integer] number of page links shown left and right
  15. # of the current page
  16. # @example: current page = 5, window = 2
  17. # |<<|1|...|3|4|[5]|6|7|...|10|>>|
  18. # @yield [text, page, status, options] block to build single paging link
  19. # @yieldparam status [Symbol] :active (for current page) or :disabled
  20. # @yieldparam page [Integer] page number, first page is 0
  21. # @return [Array<String>]
  22. 1 def build window=2, &block
  23. @render_item = block
  24. links window
  25. end
  26. 1 private
  27. 1 def links window
  28. @window_start = [@current - window, 0].max
  29. @window_end = [@current + window, @total].min
  30. left_part + window_part + right_part
  31. end
  32. # the links around the current page
  33. 1 def window_part
  34. (@window_start..@window_end).map do |page|
  35. direct_page_link page
  36. end.compact
  37. end
  38. 1 def left_part
  39. [
  40. previous_page_link,
  41. (direct_page_link 0 if @window_start > 0),
  42. (ellipse if @window_start > 1)
  43. ].compact
  44. end
  45. 1 def right_part
  46. [
  47. (ellipse if @total > @window_end + 1),
  48. (direct_page_link @total if @total > @window_end),
  49. next_page_link
  50. ].compact
  51. end
  52. 1 def previous_page_link
  53. paging_item '<span aria-hidden="true">&laquo;</span>', previous_page,
  54. "aria-label" => "Previous", status: :previous
  55. end
  56. 1 def next_page_link
  57. paging_item '<span aria-hidden="true">&raquo;</span>', next_page,
  58. "aria-label" => "Next", status: :next
  59. end
  60. 1 def direct_page_link page
  61. return unless page >= 0 && page <= @total
  62. paging_item page + 1, page
  63. end
  64. 1 def ellipse
  65. paging_item "<span>...</span>", nil, status: :ellipses
  66. end
  67. 1 def paging_item text, page, options={}
  68. status =
  69. if page == @current
  70. :current
  71. else
  72. options.delete :status
  73. end
  74. @render_item.call text, page, status, options
  75. end
  76. 1 def previous_page
  77. @current > 0 ? @current - 1 : false
  78. end
  79. 1 def next_page
  80. @current < @total ? @current + 1 : false
  81. end
  82. end
  83. end;end;end;end;
  84. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/01_paging/paging_links.rb ~~

card/tmpsets/set/mod005-pointer/abstract/02_items.rb

78.16% lines covered

87 relevant lines. 68 lines covered and 19 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (Items)
  4. #
  5. # ~~~~~~~~~~~~ READING ITEMS ~~~~~~~~~~~~
  6. 1 module Items;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/02_items.rb"; end
  9. # While each of the three main methods for returning lists of items can handle arguments,
  10. # they are most commonly used without them.
  11. # @return [Array] list of Card::Name objects
  12. # @param args [Hash]
  13. # @option args [String] :content override card content
  14. # @option args [String, Card::Name, Symbol] :context name in whose context relative items
  15. # will be interpreted. For example. +A in context of B is interpreted as B+A
  16. # context defaults to pointer card's name. If value is `:raw`, then name is not
  17. # contextualized
  18. # @option args [String, Integer] :limit max number of cards to return
  19. # @option args [String, Integer] :offset begin after the offset-th item
  20. 1 def item_names args={}
  21. 1473 context = args[:context]
  22. 1473 item_strings(args).map do |item|
  23. 1826 clean_item_name item, context
  24. end.compact
  25. end
  26. 1 def first_name args={}
  27. item_names(args).first
  28. end
  29. 1 def first_card args={}
  30. return unless (name = first_name)
  31. fetch_item_card name, args
  32. end
  33. 1 def first_code
  34. first_card&.codename
  35. end
  36. # @return [Array] list of integers (card ids of items)
  37. # @param args [Hash] see #item_names
  38. 1 def item_ids args={}
  39. 130 item_names(args).map { |name| Card.fetch_id name }.compact
  40. end
  41. # @return [Array] list of Card objects
  42. # @param args [Hash] see #item_names for additional options
  43. # @option args [String] :complete keyword to use in searching among items
  44. # @option args [True/False] :known_only if true, return only known cards
  45. # @option args [String] :type name of type to be used for unknown cards
  46. 1 def item_cards args={}
  47. 1311 return item_cards_search(args) if args[:complete]
  48. 1311 return known_item_cards(args) if args[:known_only]
  49. 1311 all_item_cards args
  50. end
  51. # #item_name, #item_id, and #item_card each return a single item, rather than an array.
  52. 1 %i[name id card].each do |obj|
  53. 3 define_method "item_#{obj}" do |args={}|
  54. 23 send("item_#{obj}s", args.merge(limit: 1)).first
  55. end
  56. end
  57. # for override, eg by json
  58. 1 def item_value item_name
  59. item_name
  60. end
  61. # ~~~~~~~~~~~~ ALTERING ITEMS ~~~~~~~~~~~~
  62. # set card content based on array and save card
  63. # @param array [Array] list of strings/names (Cardish)
  64. 1 def items= array
  65. 2 items_to_content array
  66. 2 save!
  67. end
  68. # append item to list (does not save)
  69. # @param cardish [Cardish]
  70. 1 def << cardish
  71. add_item cardish
  72. end
  73. # append item to list (does not save)
  74. # @param cardish [String, Card::Name] item name
  75. # @param allow_duplicates [True/False] permit duplicate items (default is False)
  76. 1 def add_item cardish, allow_duplicates=false
  77. return if !allow_duplicates && include_item?(cardish)
  78. items = item_strings << cardish
  79. items_to_content items
  80. end
  81. # append item to list and save card
  82. # @param name [String, Card::Name] item name
  83. 1 def add_item! name
  84. add_item(name) && save!
  85. end
  86. # remove item from list
  87. # @param cardish [String, Card::Name] item to drop
  88. 1 def drop_item cardish
  89. drop_item_name = Card::Name[cardish]
  90. items_to_content(item_names.reject { |item_name| item_name == drop_item_name })
  91. end
  92. # remove item from list and save card
  93. # @param cardish [String, Card::Name] item to drop
  94. 1 def drop_item! cardish
  95. drop_item cardish
  96. save!
  97. end
  98. # insert item into list at specified location
  99. # @param index [Integer] Array index in which to insert item (0 is first)
  100. # @param name [String, Card::Name] item name
  101. 1 def insert_item index, name
  102. 10 new_names = item_names
  103. 10 new_names.delete name
  104. 10 new_names.insert index, name
  105. 10 items_to_content new_names
  106. end
  107. # insert item into list at specified location and save
  108. # @param index [Integer] Array index in which to insert item (0 is first)
  109. # @param name [String, Card::Name] item name
  110. 1 def insert_item! index, name
  111. insert_item index, name
  112. save!
  113. end
  114. # ~~~~~~~~~~~~ READING ITEM HELPERS ~~~~~~~~~~~~
  115. # Warning: the following methods, while available for use, may be subject to change
  116. # #item_cards helpers
  117. 1 def item_cards_search query
  118. Card::Query.run query.reverse_merge(referred_to_by: name, limit: 0)
  119. end
  120. 1 def known_item_cards args={}
  121. item_names(args).map { |name| Card.fetch name }.compact
  122. end
  123. 1 def all_item_cards args={}
  124. 1311 names = args[:item_names] || item_names(args)
  125. 2632 names.map { |name| fetch_item_card name, args }
  126. end
  127. # TODO: support type_code and type_id. (currently type)
  128. # uses name, because its most common use is from CQL
  129. 1 def item_type
  130. 1321 opt = options_rule_card
  131. # FIXME: need better recursion prevention
  132. 1321 return if !opt || opt == self
  133. 1305 opt.item_type
  134. end
  135. 1 def item_strings args={}
  136. 1481 items = raw_item_strings(args[:content] || content)
  137. 1481 return items unless args.present?
  138. 36 filtered_items items, args.slice(:limit, :offset)
  139. end
  140. 1 def raw_item_strings content
  141. 3313 content.to_s.split(/\n+/).map { |i| strip_item i }
  142. end
  143. 1 private
  144. 1 def filtered_items items, limit: 0, offset: 0
  145. 36 limit = limit.to_i
  146. 36 offset = offset.to_i
  147. 36 return items unless limit.positive? || offset.positive?
  148. 23 items[offset, (limit.zero? ? items.size : limit)] || []
  149. end
  150. 1 def fetch_item_card name, args={}
  151. 1321 Card.fetch name, new: new_unknown_item_args(args)
  152. end
  153. 1 def new_unknown_item_args args
  154. 1321 itype = args[:type] || item_type
  155. 1321 itype ? { type: itype } : {}
  156. end
  157. 1 def clean_item_name item, context
  158. 1826 item = item.to_name
  159. 1826 return item if context == :raw
  160. 1826 context ||= context_card.name
  161. 1826 item.absolute_name context
  162. rescue Card::Error::NotFound
  163. # eg for invalid ids or codenames
  164. # "Invalid Item: #{item}".to_name
  165. nil
  166. end
  167. 1 def strip_item item
  168. 1832 item.gsub(/\[\[|\]\]/, "").strip
  169. end
  170. end;end;end;end;
  171. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/02_items.rb ~~

card/tmpsets/set/mod005-pointer/abstract/02_pointer.rb

80.0% lines covered

10 relevant lines. 8 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (Pointer)
  4. #
  5. 1 module Pointer;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/02_pointer.rb"; end
  8. 1 include_set Abstract::Paging
  9. 1 include_set Abstract::Items
  10. 1 def diff_args
  11. { diff_format: :pointer }
  12. end
  13. 1 def count
  14. item_strings.size
  15. end
  16. end;end;end;end;
  17. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/02_pointer.rb ~~

card/tmpsets/set/mod005-pointer/abstract/02_pointer/events.rb

57.89% lines covered

38 relevant lines. 22 lines covered and 16 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Abstract; module Pointer;
  3. # Set: Abstract (Pointer, Events)
  4. #
  5. 1 module Events;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/02_pointer/events.rb"; end
  8. 1 event :add_and_drop_items, :prepare_to_validate, on: :save do
  9. 35 adds = Env.params["add_item"]
  10. 35 drops = Env.params["drop_item"]
  11. 35 Array.wrap(adds).each { |i| add_item i } if adds
  12. 35 Array.wrap(drops).each { |i| drop_item i } if drops
  13. end
  14. 1 event :insert_item_event, :prepare_to_validate, on: :save, when: :item_to_insert do
  15. index = Env.params["item_index"] || 0
  16. insert_item index.to_i, item_to_insert
  17. end
  18. 1 def item_to_insert
  19. 35 Env.params["insert_item"]
  20. end
  21. # If a card's type and content are updated in the same action, the new module
  22. # will override the old module's events and functions. But this event is only
  23. # on pointers -- other type cards do not have this event,
  24. # Therefore if something is changed from a pointer and its content is changed
  25. # in the same action, this event will be run and will treat the content like
  26. # it' still pointer content. The "when" clause helps with that (but is a hack)
  27. 1 event :standardize_items, :prepare_to_validate,
  28. on: :save, changed: :content, when: :still_pointer? do
  29. 8 items_to_content item_strings
  30. end
  31. 1 def still_pointer?
  32. 28 type_id == PointerID
  33. # Card.new(type_id: type_id).is_a? Abstract::Pointer
  34. end
  35. 1 def changed_item_names
  36. dropped_item_names + added_item_names
  37. end
  38. 1 def dropped_item_names
  39. return item_names if trash
  40. return [] unless (old_content = db_content_before_act)
  41. old_items = item_names content: old_content
  42. old_items - item_names
  43. end
  44. 1 def added_item_names
  45. return [] if trash
  46. return item_names unless (old_content = db_content_before_act)
  47. old_items = item_names content: old_content
  48. item_names - old_items
  49. end
  50. # TODO: refactor. many of the above could be written more elegantly with improved
  51. # handling of :content in item_names. If content is nil here, we would expect an
  52. # empty set of cards, but in fact we get items based on self.content.
  53. 1 def changed_item_cards
  54. dropped_item_cards + added_item_cards
  55. end
  56. 1 def dropped_item_cards
  57. return [] unless db_content_before_act
  58. all_item_cards item_names: dropped_item_names
  59. end
  60. 1 def added_item_cards
  61. return item_cards unless db_content_before_act
  62. all_item_cards item_names: added_item_names
  63. end
  64. end;end;end;end;end;
  65. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/02_pointer/events.rb ~~

card/tmpsets/set/mod005-pointer/abstract/02_pointer/html_views.rb

49.18% lines covered

61 relevant lines. 30 lines covered and 31 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Abstract; module Pointer;
  3. # Set: Abstract (Pointer, HtmlViews)
  4. #
  5. 1 module HtmlViews;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/02_pointer/html_views.rb"; end
  8. 1 include_set Abstract::BsBadge
  9. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  10. 1 view :core, cache: :never do
  11. standard_pointer_core
  12. end
  13. 1 view :item_cores, cache: :never do
  14. card.known_item_cards.map do |item|
  15. nest item, view: :core
  16. end.join "\n"
  17. end
  18. 1 def standard_pointer_core
  19. with_paging do |paging_args|
  20. wrap_with :div, standard_pointer_items(paging_args), class: "pointer-list"
  21. end
  22. end
  23. 1 def standard_pointer_items paging_args
  24. pointer_items(paging_args.extract!(:limit, :offset)).join(voo.separator || "\n")
  25. end
  26. 1 view :one_line_content do
  27. item_view = implicit_item_view
  28. item_view = item_view == "name" ? "name" : "link"
  29. wrap_with :div, class: "pointer-list" do
  30. # limit to first 10 items to optimize
  31. pointer_items(view: item_view, limit: 10, offset: 0).join ", "
  32. end
  33. end
  34. 1 def wrap_item rendered, item_view
  35. %(<div class="pointer-item item-#{item_view}">#{rendered}</div>)
  36. end
  37. 1 view :input do
  38. 12 _render_hidden_content_field + super()
  39. end
  40. 1 def default_input_type
  41. :list
  42. end
  43. 1 view :list, cache: :never do
  44. list_input
  45. end
  46. # view :nav_item do
  47. # nav_dropdown
  48. # end
  49. 1 def list_input args={}
  50. items = items_for_input args[:item_list]
  51. extra_class = "pointer-list-ul"
  52. ul_classes = classy "pointer-list-editor", extra_class
  53. haml :list_input, items: items, ul_classes: ul_classes,
  54. options_card: options_card_name
  55. end
  56. 1 %i[autocomplete checkbox radio select multiselect].each do |editor_view|
  57. 5 view(editor_view) { send "#{editor_view}_input" }
  58. end
  59. 1 def autocomplete_input
  60. items = items_for_input
  61. haml :autocomplete_input, item: items.first, options_card: options_card_name
  62. end
  63. 1 def checkbox_input
  64. haml :checkbox_input, submit_on_change: @submit_on_change
  65. end
  66. 1 def radio_input
  67. haml :radio_input, submit_on_change: @submit_on_change
  68. end
  69. 1 def select_input
  70. options = { "-- Select --" => "" }.merge card.options_hash
  71. select_tag("pointer_select-#{unique_id}",
  72. options_for_select(options, card.item_name),
  73. class: "pointer-select form-control")
  74. end
  75. 1 def multiselect_input
  76. select_tag "pointer_multiselect-#{unique_id}",
  77. options_for_select(card.options_hash, card.item_names),
  78. multiple: true, class: "pointer-multiselect form-control"
  79. end
  80. 1 def add_item_modal_link
  81. modal_link "Add Item",
  82. size: :large,
  83. class: "btn btn-sm btn-outline-secondary _add-item-link",
  84. path: { view: :filter_items_modal,
  85. item: implicit_item_view,
  86. filter_card: filter_card.name,
  87. slot_selector: filtered_list_slot_class,
  88. item_selector: "_filtered-list-item",
  89. slot: { hide: [:modal_footer] },
  90. filter: { not_ids: not_ids_value } }
  91. end
  92. 1 def not_ids_value
  93. card.item_ids.map(&:to_s).join(",")
  94. end
  95. 1 def add_item_overlay_link; end
  96. 1 def one_line_content
  97. if count == 1
  98. card.first_name
  99. else
  100. short_content
  101. end
  102. end
  103. 1 private
  104. # currently only used by :list and :autocomplete. could be generalized?
  105. 1 def items_for_input items=nil
  106. items ||= card.item_names context: :raw
  107. items.empty? ? [""] : items
  108. end
  109. end
  110. end;end;end;end;end;
  111. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/02_pointer/html_views.rb ~~

card/tmpsets/set/mod005-pointer/abstract/02_pointer/html_views/filter.rb

46.88% lines covered

32 relevant lines. 15 lines covered and 17 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 5 class Card; module Set; class Abstract; module Pointer;; module HtmlViews;
  3. # Set: Abstract (Pointer, HtmlViews, Filter)
  4. #
  5. 1 module Filter;
  6. 1 extend Card::Set
  7. 2 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/02_pointer/html_views/filter.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :filtered_list, unknown: true do
  10. filtered_list_input
  11. end
  12. 1 view :filter_items_modal, unknown: true, wrap: :modal do
  13. render_filter_items
  14. end
  15. 1 view :filter_items, unknown: true, wrap: :slot, template: :haml
  16. 1 def filtered_list_input
  17. with_nest_mode :normal do
  18. class_up "card-slot", filtered_list_slot_class
  19. with_class_up "card-slot", filtered_list_slot_class do
  20. wrap do
  21. haml :filtered_list_input
  22. end
  23. end
  24. end
  25. end
  26. # NOCACHE because params alter view
  27. 1 view :add_selected_link, cache: :never, unknown: true do
  28. link_to "Add Selected",
  29. path: { filter_card: params[:filter_card] },
  30. class: "_add-selected slotter _close-modal btn btn-primary disabled",
  31. data: { "slot-selector": ".#{params[:slot_selector]}",
  32. "item-selector": ".#{params[:item_selector]}",
  33. remote: true }
  34. end
  35. 1 def filtered_list_item item_card
  36. nest_item item_card do |rendered, item_view|
  37. wrap_item rendered, item_view
  38. end
  39. end
  40. # for override
  41. # @return [Card] search card on which filtering is based
  42. 1 def filter_card
  43. filter_card_from_params || default_filter_card
  44. end
  45. 1 def default_filter_card
  46. fcard = card.options_rule_card || Card[:all]
  47. return fcard if fcard.respond_to? :cql_hash
  48. fcard.fetch :referred_to_by, new: {}
  49. end
  50. 1 def filter_card_from_params
  51. return unless params[:filter_card]
  52. Card.fetch params[:filter_card], new: {}
  53. end
  54. # currently actually used as a class
  55. # (because we don't have api to override slot's id)
  56. 1 def filtered_list_slot_class
  57. @filtered_list_slot_class ||= "filtered-list-#{unique_id}"
  58. end
  59. end
  60. end;end;end;end;end;end;
  61. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/02_pointer/html_views/filter.rb ~~

card/tmpsets/set/mod005-pointer/abstract/02_pointer/options_api.rb

48.84% lines covered

43 relevant lines. 21 lines covered and 22 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Abstract; module Pointer;
  3. # Set: Abstract (Pointer, OptionsApi)
  4. #
  5. # TODO: some of this should be moved to right/options!!
  6. 1 module OptionsApi;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/02_pointer/options_api.rb"; end
  9. # or to type/JSON?
  10. 1 def options_hash
  11. json_options? ? options_card.parse_content : option_hash_from_names
  12. end
  13. 1 def json_options?
  14. options_card&.type_id == JsonID
  15. end
  16. 1 def option_hash_from_names
  17. option_names.each_with_object({}) do |name, hash|
  18. hash[name] = name
  19. end
  20. end
  21. 1 def option_names
  22. if (selected_options = item_names)
  23. (standard_option_names + selected_options).uniq
  24. else
  25. standard_option_names
  26. end
  27. end
  28. 1 def option_cards
  29. option_names.map do |name|
  30. Card.fetch name, new: {}
  31. end
  32. end
  33. 1 def options_rule_card
  34. 20 rule_card :content_options
  35. end
  36. 1 def standard_option_names
  37. if json_options?
  38. options_hash.values.map(&:to_name)
  39. else
  40. option_names_from_items
  41. end
  42. end
  43. 1 def option_names_from_items
  44. o_card = options_card
  45. limit = o_card.try(:default_limit).to_i
  46. o_card.item_names context: name, limit: limit
  47. end
  48. 1 def options_card
  49. options_rule_card || Card[:all]
  50. end
  51. 1 def options_card_name
  52. options_rule_card&.name&.url_key || ":all"
  53. end
  54. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  55. 1 def options_card_name
  56. card.options_card_name
  57. end
  58. end
  59. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  60. 1 def option_label option_name, id
  61. %(<label for="#{id}">#{option_label_text option_name}</label>)
  62. end
  63. 1 def option_view
  64. @option_view ||= card.rule(:content_option_view) || :smart_label
  65. end
  66. 1 def option_label_text option_name
  67. return option_name unless (option_card = Card.fetch option_name)
  68. nest option_card, view: option_view
  69. end
  70. end
  71. end;end;end;end;end;
  72. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/02_pointer/options_api.rb ~~

card/tmpsets/set/mod005-pointer/abstract/02_pointer/other_views.rb

56.0% lines covered

50 relevant lines. 28 lines covered and 22 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Abstract; module Pointer;
  3. # Set: Abstract (Pointer, OtherViews)
  4. #
  5. # BASE views
  6. 1 module OtherViews;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/02_pointer/other_views.rb"; end
  9. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  10. 1 def default_limit
  11. 20
  12. end
  13. 1 def item_links args={}
  14. card.item_cards(args).map do |item_card|
  15. subformat(item_card).render_link
  16. end
  17. end
  18. 1 def nest_item_array
  19. card.item_cards.map do |item|
  20. nest_item item
  21. end
  22. end
  23. 1 view :core do
  24. pointer_items.join ", "
  25. end
  26. 1 def pointer_items args={}
  27. page_args = args.extract! :limit, :offset
  28. listing card.item_cards(page_args), args
  29. end
  30. end
  31. # JavaScript views
  32. 2 module JsFormat; module_parent.send :register_set_format, Card::Format::JsFormat, self; extend Card::Set::AbstractFormat
  33. 1 view :core do
  34. nest_item_array.join "\n\n"
  35. end
  36. end
  37. # Data views
  38. 2 module DataFormat; module_parent.send :register_set_format, Card::Format::DataFormat, self; extend Card::Set::AbstractFormat
  39. 1 view :core do
  40. nest_item_array
  41. end
  42. end
  43. # JSON views
  44. 2 module JsonFormat; module_parent.send :register_set_format, Card::Format::JsonFormat, self; extend Card::Set::AbstractFormat
  45. 1 view :content do
  46. card.item_names
  47. end
  48. 1 def item_cards
  49. card.item_cards
  50. end
  51. 1 def max_depth
  52. params[:max_depth] || 1
  53. end
  54. 1 def items_for_export
  55. card.item_cards
  56. end
  57. 1 def essentials
  58. return {} if depth > max_depth
  59. card.item_cards.map do |item|
  60. nest item, view: :essentials
  61. end
  62. end
  63. 1 view :links do
  64. []
  65. end
  66. end
  67. # CSS views
  68. 2 module CssFormat; module_parent.send :register_set_format, Card::Format::CssFormat, self; extend Card::Set::AbstractFormat
  69. # generalize to all collections?
  70. 1 def default_item_view
  71. :content
  72. end
  73. 1 view :titled do
  74. %(#{major_comment "STYLE GROUP: \"#{card.name}\"", '='}#{_render_core})
  75. end
  76. 1 view :core do
  77. nest_item_array.join "\n\n"
  78. end
  79. 1 view :content, :core
  80. end
  81. # RSS views
  82. 2 module RssFormat; module_parent.send :register_set_format, Card::Format::RssFormat, self; extend Card::Set::AbstractFormat
  83. 1 def raw_feed_items
  84. @raw_feed_items ||= card.item_cards(limit: limit, offset: offset)
  85. end
  86. end
  87. end;end;end;end;end;
  88. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/02_pointer/other_views.rb ~~

card/tmpsets/set/mod005-pointer/abstract/code_pointer.rb

85.0% lines covered

20 relevant lines. 17 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (CodePointer)
  4. #
  5. 1 module CodePointer;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/code_pointer.rb"; end
  8. 1 include_set Abstract::Pointer
  9. 1 abstract_basket :item_codenames
  10. # simplify api
  11. # Self::MyCodePointerSet.add_item :my_item_codename
  12. # instead of
  13. # Self::MyCodePointerSet.add_to_basket :item_codenames, :my_item_codename
  14. 1 module ClassMethods
  15. 1 def add_item codename
  16. 21 valid_codename codename do
  17. 21 add_to_basket :item_codenames, codename
  18. end
  19. end
  20. 1 def unshift_item codename
  21. valid_codename codename do
  22. unshift_basket :item_codenames, codename
  23. end
  24. end
  25. 1 def valid_codename codename
  26. 21 if Card::Codename.exist? codename
  27. 21 yield
  28. else
  29. Rails.logger.info "unknown codename '#{codename}' added to code pointer"
  30. end
  31. end
  32. end
  33. 1 def content
  34. 4 item_codenames.map do |codename|
  35. 14 Card.fetch_name codename
  36. end.compact.to_pointer_content
  37. end
  38. end;end;end;end;
  39. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/code_pointer.rb ~~

card/tmpsets/set/mod005-pointer/abstract/id_pointer.rb

50.0% lines covered

14 relevant lines. 7 lines covered and 7 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (IdPointer)
  4. #
  5. # store items as ids, not names
  6. 1 module IdPointer;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/id_pointer.rb"; end
  9. 1 def standardize_item cardish
  10. if (id = Card.fetch_id cardish)
  11. "~#{id}"
  12. else
  13. Rails.logger.info "no id for '#{cardish}' added to id pointer"
  14. nil
  15. end
  16. end
  17. 1 def item_ids args={}
  18. item_strings(args).map do |item|
  19. item = standardize_item item unless item.match?(/^~/)
  20. item.to_s.tr("~", "").to_i
  21. end.compact
  22. end
  23. 1 def item_names args={}
  24. item_ids(args).map(&:cardname).compact
  25. end
  26. end;end;end;end;
  27. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/abstract/id_pointer.rb ~~

card/tmpsets/set/mod005-pointer/right/content_options.rb

71.43% lines covered

7 relevant lines. 5 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+ContentOptions" cards
  4. #
  5. 1 module ContentOptions;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/right/content_options.rb"; end
  8. 1 def default_limit
  9. cql_limit = fetch_query.limit if respond_to?(:fetch_query)
  10. cql_limit || 50
  11. end
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/right/content_options.rb ~~

card/tmpsets/set/mod005-pointer/self/input_options.rb

92.86% lines covered

14 relevant lines. 13 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "InputOptions"
  4. #
  5. 1 module InputOptions;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/self/input_options.rb"; end
  8. 1 include_set Abstract::Pointer
  9. 1 basket :options
  10. 1 add_to_basket :options, "radio"
  11. 1 add_to_basket :options, "checkbox"
  12. 1 add_to_basket :options, "select"
  13. 1 add_to_basket :options, "multiselect"
  14. 1 add_to_basket :options, "list"
  15. 1 add_to_basket :options, "filtered list"
  16. 1 def content
  17. options.to_pointer_content
  18. end
  19. end;end;end;end;
  20. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/self/input_options.rb ~~

card/tmpsets/set/mod005-pointer/self/script_editors.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ScriptEditors"
  4. #
  5. 1 module ScriptEditors;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/self/script_editors.rb"; end
  8. 1 include_set Abstract::CodePointer
  9. end;end;end;end;
  10. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/self/script_editors.rb ~~

card/tmpsets/set/mod005-pointer/self/script_libraries.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ScriptLibraries"
  4. #
  5. 1 module ScriptLibraries;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/self/script_libraries.rb"; end
  8. 1 include_set Abstract::CodePointer
  9. end;end;end;end;
  10. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/self/script_libraries.rb ~~

card/tmpsets/set/mod005-pointer/self/script_mods.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ScriptMods"
  4. #
  5. 1 module ScriptMods;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/self/script_mods.rb"; end
  8. 1 include_set Abstract::CodePointer
  9. end;end;end;end;
  10. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/self/script_mods.rb ~~

card/tmpsets/set/mod005-pointer/self/script_pointer_config.rb

88.89% lines covered

9 relevant lines. 8 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ScriptPointerConfig"
  4. #
  5. 1 module ScriptPointerConfig;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/self/script_pointer_config.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 FILE_NAMES = %w[pointer_config pointer_list_editor]
  10. 1 def source_files
  11. coffee_files FILE_NAMES
  12. end
  13. 1 Self::ScriptEditors.add_item :script_pointer_config
  14. end;end;end;end;
  15. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/self/script_pointer_config.rb ~~

card/tmpsets/set/mod005-pointer/self/style_libraries.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "StyleLibraries"
  4. #
  5. 1 module StyleLibraries;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/self/style_libraries.rb"; end
  8. 1 include_set Abstract::CodePointer
  9. end;end;end;end;
  10. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/self/style_libraries.rb ~~

card/tmpsets/set/mod005-pointer/self/style_mods.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "StyleMods"
  4. #
  5. 1 module StyleMods;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/self/style_mods.rb"; end
  8. 1 include_set Abstract::CodePointer
  9. end;end;end;end;
  10. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/self/style_mods.rb ~~

card/tmpsets/set/mod005-pointer/type/link_list.rb

53.85% lines covered

26 relevant lines. 14 lines covered and 12 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "LinkList" cards
  4. #
  5. 1 module LinkList;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/type/link_list.rb"; end
  8. 1 include_set Abstract::Pointer
  9. 1 def raw_item_strings content
  10. reference_chunks(content).map(&:referee_name)
  11. end
  12. 1 def item_titles default_to_name=true
  13. reference_chunks.map do |chunk|
  14. chunk.options[:title] || (default_to_name ? chunk.referee_name : nil)
  15. end
  16. end
  17. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  18. 1 def chunk_list
  19. :references
  20. end
  21. end
  22. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  23. 1 def input_type
  24. :link_list
  25. end
  26. 1 view :link_list_input, cache: :never do
  27. link_list_input
  28. end
  29. 1 def items_for_input items=nil
  30. items ||= card.item_names context: :raw
  31. items.empty? ? [["", ""]] : items.zip(card.item_titles(false))
  32. end
  33. 1 def link_list_input args={}
  34. items = items_for_input args[:item_list]
  35. extra_class = "pointer-link-list-ul"
  36. ul_classes = classy "pointer-list-editor", extra_class
  37. haml :link_list_input, items: items, ul_classes: ul_classes,
  38. options_card: options_card_name
  39. end
  40. end
  41. end;end;end;end;
  42. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/type/link_list.rb ~~

card/tmpsets/set/mod005-pointer/type/list.rb

76.92% lines covered

13 relevant lines. 10 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "List" cards
  4. #
  5. 1 module List;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/type/list.rb"; end
  8. 1 include_set Abstract::Pointer
  9. 1 def each_reference_out
  10. 18 item_names.each do |name|
  11. 147 yield(name, Card::Content::Chunk::Link::CODE)
  12. end
  13. end
  14. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  15. 1 view :view_list do
  16. %i[info_bar bar box closed titled labeled].map do |view|
  17. voo.items[:view] = view
  18. wrap_with :p, [content_tag(:h3, "#{view} items"), render_content]
  19. end
  20. end
  21. end
  22. end;end;end;end;
  23. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/type/list.rb ~~

card/tmpsets/set/mod005-pointer/type/mirror_list.rb

36.73% lines covered

49 relevant lines. 18 lines covered and 31 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "MirrorList" cards
  4. #
  5. 1 module MirrorList;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/type/mirror_list.rb"; end
  8. 1 include_set Abstract::Pointer
  9. 1 event :validate_listed_by_name, :validate, on: :save, changing: :name do
  10. if !junction? || !right || right.type_id != Card::CardtypeID
  11. errors.add :name, tr(:cardtype_right)
  12. end
  13. end
  14. 1 event :validate_listed_by_content, :validate,
  15. on: :save, changing: :content do
  16. item_cards(content: content).each do |item_card|
  17. next unless item_card.type_id != right.id
  18. errors.add(
  19. :content,
  20. "#{item_card.name} has wrong cardtype; " \
  21. "only cards of type #{name.right} are allowed"
  22. )
  23. end
  24. end
  25. 1 event :update_content_in_list_cards, :prepare_to_validate,
  26. on: :save, changing: :content do
  27. return unless db_content.present?
  28. new_items = item_keys(content: db_content)
  29. old_items = item_keys(content: old_content)
  30. remove_items(old_items - new_items)
  31. add_items(new_items - old_items)
  32. end
  33. 1 def old_content
  34. db_content_before_act.present? ? db_content_before_act : content_cache.read(key)
  35. end
  36. 1 def remove_items items
  37. items.each do |item|
  38. next unless (lc = list_card item)
  39. lc.drop_item name.left
  40. subcards.add lc
  41. end
  42. end
  43. 1 def add_items items
  44. items.each do |item|
  45. if (lc = list_card(item))
  46. lc.add_item name.left
  47. subcards.add lc
  48. else
  49. subcards.add(name: "#{Card[item].name}+#{left.type_name}",
  50. type: "list",
  51. content: "[[#{name.left}]]")
  52. end
  53. end
  54. end
  55. 1 def content_cache
  56. Card::Cache[Card::Set::Type::MirrorList]
  57. end
  58. 1 def content
  59. content_cache.fetch(key) do
  60. generate_content
  61. end
  62. end
  63. 1 def generate_content
  64. listed_by.map do |item|
  65. "[[%s]]" % item.to_name.left
  66. end.join "\n"
  67. end
  68. 1 def listed_by
  69. Card.search(
  70. { type_id: Card::MirroredListID, right: trunk.type_name,
  71. left: { type: name.tag }, refer_to: name.trunk, return: :name },
  72. "all cards listed by #{name}"
  73. )
  74. end
  75. 1 def update_cached_list
  76. if trunk
  77. Card::Cache[Card::Set::Type::MirrorList].write key, generate_content
  78. else
  79. Card::Cache[Card::Set::Type::MirrorList].delete key
  80. end
  81. end
  82. 1 def list_card item
  83. Card.fetch item, left.type_name
  84. end
  85. 1 def unfilled?
  86. false
  87. end
  88. end;end;end;end;
  89. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/type/mirror_list.rb ~~

card/tmpsets/set/mod005-pointer/type/mirrored_list.rb

31.75% lines covered

63 relevant lines. 20 lines covered and 43 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "MirroredList" cards
  4. #
  5. 1 module MirroredList;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/type/mirrored_list.rb"; end
  8. 1 include_set Abstract::Pointer
  9. 1 event :validate_list_name, :validate, on: :save, changed: :name do
  10. errors.add :name, tr(:cardtype_right) unless right&.type_id == Card::CardtypeID
  11. end
  12. 1 event :validate_list_item_type_change, :validate,
  13. on: :save, changed: :name do
  14. item_cards.each do |item_card|
  15. next unless item_card.type_name.key != item_type_name.key
  16. errors.add :name, tr(:conflict_item_type)
  17. end
  18. end
  19. 1 event :validate_list_content, :validate,
  20. on: :save, changed: :content do
  21. item_cards.each do |item_card|
  22. next unless item_card.type_name.key != item_type_name.key
  23. errors.add :content, tr(
  24. :only_type_allowed,
  25. cardname: item_card.name,
  26. cardtype: name.right
  27. )
  28. end
  29. end
  30. 1 event :create_listed_by_cards, :prepare_to_validate,
  31. on: :save, changed: :content do
  32. item_names.each do |item_name|
  33. listed_by_name = "#{item_name}+#{left.type_name}"
  34. next if director.main_director.card.key == listed_by_name.to_name.key
  35. if !Card[listed_by_name]
  36. add_subcard listed_by_name, type_id: Card::MirrorListID
  37. else
  38. Card[listed_by_name].update_references_out
  39. end
  40. end
  41. end
  42. 1 event :update_related_listed_by_card_on_create, :finalize,
  43. on: :create do
  44. update_listed_by_cache_for item_keys
  45. end
  46. 1 event :update_related_listed_by_card_on_content_update, :finalize,
  47. on: :update, changed: :content do
  48. new_items = item_keys
  49. changed_items =
  50. if db_content_before_act
  51. old_items = item_keys(content: db_content_before_act)
  52. old_items + new_items - (old_items & new_items)
  53. else
  54. new_items
  55. end
  56. update_listed_by_cache_for changed_items
  57. end
  58. 1 event :update_related_listed_by_card_on_name_and_type_changes, :finalize,
  59. on: :update, changed: %i[name type_id] do
  60. update_all_items
  61. end
  62. 1 event :update_related_listed_by_card_on_delete, :finalize,
  63. on: :delete, when: proc { |c| c.junction? } do
  64. update_listed_by_cache_for item_keys, type_key: @left_type_key
  65. end
  66. 1 event :cache_type_key, :store,
  67. on: :delete, when: proc { |c| c.junction? } do
  68. @left_type_key = left.type_card.key
  69. end
  70. 1 def update_all_items
  71. current_items = item_keys
  72. if db_content_before_act
  73. old_items = item_keys(content: db_content_before_act)
  74. update_listed_by_cache_for old_items
  75. end
  76. update_listed_by_cache_for current_items
  77. end
  78. 1 def update_listed_by_cache_for item_keys, args={}
  79. type_key = args[:type_key] || left&.type_card&.key
  80. return unless type_key
  81. item_keys.each do |item_key|
  82. key = "#{item_key}+#{type_key}"
  83. next unless Card::Cache[Card::Set::Type::MirrorList].exist? key
  84. if (card = Card.fetch(key)) && card.left
  85. card.update_cached_list
  86. card.update_references_out
  87. else
  88. Card::Cache[Card::Set::Type::MirrorList].delete key
  89. end
  90. end
  91. end
  92. 1 def item_type
  93. name.right
  94. end
  95. 1 def item_type_name
  96. name.right_name
  97. end
  98. 1 def item_type_card
  99. name.right
  100. end
  101. 1 def item_type_id
  102. right.id
  103. end
  104. end;end;end;end;
  105. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/type/mirrored_list.rb ~~

card/tmpsets/set/mod005-pointer/type/nest_list.rb

53.33% lines covered

30 relevant lines. 16 lines covered and 14 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "NestList" cards
  4. #
  5. 1 module NestList;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/type/nest_list.rb"; end
  8. 1 include_set Abstract::Items
  9. 1 def raw_item_strings content
  10. reference_chunks(content).map(&:referee_name)
  11. end
  12. 1 def item_options
  13. nest_chunks.map(&:raw_options)
  14. end
  15. 1 def items_to_content array
  16. items = array.map { |i| standardize_item i }.reject(&:blank?)
  17. self.content = items.join("\n")
  18. end
  19. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  20. 1 def chunk_list
  21. :references
  22. end
  23. end
  24. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  25. 1 def input_type
  26. :nest_list
  27. end
  28. 1 view :nest_list_input, cache: :never do
  29. nest_list_input
  30. end
  31. 1 view :input do
  32. _render_hidden_content_field + super()
  33. end
  34. 1 def items_for_input items=nil
  35. items ||= card.item_names context: :raw
  36. items.empty? ? [["", ""]] : items.zip(card.item_options)
  37. end
  38. 1 def nest_list_input args={}
  39. items = items_for_input args[:item_list]
  40. extra_class = "_nest-list-ul"
  41. ul_classes = classy "pointer-list-editor", extra_class
  42. haml :nest_list_input, items: items, ul_classes: ul_classes
  43. end
  44. end
  45. end;end;end;end;
  46. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/type/nest_list.rb ~~

card/tmpsets/set/mod005-pointer/type/pointer.rb

70.0% lines covered

10 relevant lines. 7 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Pointer" cards
  4. #
  5. 1 module Pointer;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/pointer/set/type/pointer.rb"; end
  8. 1 include_set Abstract::Pointer
  9. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  10. 1 view :view_list do
  11. %i[info_bar bar box closed titled labeled].map do |view|
  12. voo.items[:view] = view
  13. wrap_with :p, [content_tag(:h3, "#{view} items"), render_content]
  14. end
  15. end
  16. end
  17. end;end;end;end;
  18. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/pointer/set/type/pointer.rb ~~

card/tmpsets/set/mod006-card-mod-virtual/abstract/virtual_cache.rb

79.17% lines covered

24 relevant lines. 19 lines covered and 5 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (VirtualCache)
  4. #
  5. # -*- encoding : utf-8 -*-
  6. 1 module VirtualCache;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-virtual/set/abstract/virtual_cache.rb"; end
  9. 1 def virtual?
  10. 2 new?
  11. end
  12. 1 def history?
  13. 1 false
  14. end
  15. 1 def followable?
  16. false
  17. end
  18. 1 def db_content
  19. 2 Card::Virtual.fetch_content(self)
  20. end
  21. # called to refresh the virtual content
  22. # the default way is to use the card's template content
  23. 1 def generate_virtual_content
  24. 1 template&.db_content
  25. end
  26. 1 event :save_virtual_content, :prepare_to_store, on: :save, changed: :content do
  27. 1 Card::Virtual.create_or_update(self, attributes["db_content"])
  28. 1 abort :success
  29. end
  30. 1 event :delete_virtual_content, :prepare_to_store, on: :delete do
  31. Card::Virtual.find_by_card(self)&.delete
  32. abort :success
  33. end
  34. 1 def delete
  35. # delete although it's new
  36. update trash: true
  37. end
  38. 1 def delete!
  39. # delete although it's new
  40. update! trash: true
  41. end
  42. end;end;end;end;
  43. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-virtual/set/abstract/virtual_cache.rb ~~

card/tmpsets/set/mod007-card-mod-machines/abstract/machine.rb

84.68% lines covered

111 relevant lines. 94 lines covered and 17 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (Machine)
  4. #
  5. # ## What are Machines?
  6. # {Machine} and {MachineInput} together implement a kind of observer pattern.
  7. # {Machine} processes a collection of input cards to generate an output card
  8. # (a {Set::Type::File} card by default). If one of the input cards is changed
  9. # the output card will be updated.
  10. #
  11. # The classic example: A style card observes a collection of css and sccs card
  12. # to generate a file card with a css file that contains the assembled
  13. # compressed css.
  14. #
  15. # ## Using Machines
  16. # Include the Machine module in the card set that is supposed to produce the
  17. # output card. If the output card should be automatically updated when a input
  18. # card is changed the input card has to be in a set that includes the
  19. # MachineInput module.
  20. #
  21. # The default machine:
  22. 1 module Machine;
  23. 1 extend Card::Set
  24. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/abstract/machine.rb"; end
  25. #
  26. # - uses its item cards as input cards or the card itself if there are no
  27. # item cards;
  28. # - can be changed by passing a block to collect_input_cards
  29. # - takes the raw view of the input cards to generate the output;
  30. # - can be changed by passing a block to machine_input (in the input card
  31. # set)
  32. # - stores the output as a .txt file in the '+machine output' card;
  33. # - can be changed by passing a filetype and/or a block to
  34. # store_machine_output
  35. #
  36. #
  37. # ## How does it work?
  38. # Machine cards have a '+machine input' and a '+machine output' card. The
  39. # '+machine input' card is a pointer to all input cards. Including the
  40. # MachineInput module creates an 'on: save' event that runs the machines of
  41. # all cards that are linked to that card via the +machine input pointer.
  42. 1 module MachineClassMethods
  43. 1 attr_accessor :output_config
  44. 1 def collect_input_cards &block
  45. define_method :engine_input, &block
  46. end
  47. 1 def prepare_machine_input &block
  48. define_method :before_engine, &block
  49. end
  50. 1 def machine_engine &block
  51. define_method :engine, &block
  52. end
  53. 1 def store_machine_output args={}, &block
  54. 5 output_config.merge!(args)
  55. 5 return unless block_given?
  56. define_method :after_engine, &block
  57. end
  58. end
  59. 1 card_accessor :machine_output, type: FileID
  60. 1 card_accessor :machine_input, type: PointerID
  61. 1 def before_engine
  62. end
  63. 1 def engine_input
  64. 2 ei = EngineInput.new self
  65. 2 ei.process
  66. 2 ei.new_input
  67. end
  68. # TODO: replace with call of extended_item_cards
  69. # traverse through all levels of pointers and
  70. # collect all item cards as input
  71. 1 class EngineInput
  72. 1 attr_accessor :new_input
  73. 1 def initialize machine_card
  74. 2 @machine_card = machine_card
  75. 2 @items = [machine_card]
  76. 2 @new_input = []
  77. 2 @extended = {}
  78. 2 @loop_limit = 5
  79. end
  80. 1 def process
  81. 2 each_valid_item do
  82. 4 input_item = simple_item? ? @item : pointer_item
  83. 4 new_input << input_item if input_item
  84. end
  85. end
  86. 1 def simple_item?
  87. 4 @item.item_cards == [@item] # no pointer card
  88. end
  89. 1 def pointer_item
  90. 2 @items.insert 0, @item.item_cards.reject(&:unknown?)
  91. 2 @items.flatten!
  92. 2 record_item
  93. 2 @item if @item != @machine_card && @item.known?
  94. end
  95. 1 def record_item
  96. 2 @extended[@item] = @extended[@item].to_i + 1
  97. end
  98. 1 def each_valid_item
  99. 2 until @items.empty?
  100. 4 @item = @items.shift
  101. 4 yield unless invalid_item?
  102. end
  103. end
  104. 1 def invalid_item?
  105. 4 @item.trash || @extended[@item.id].to_i > @loop_limit
  106. end
  107. end
  108. 1 def engine input
  109. 1 input
  110. end
  111. 1 def after_engine output
  112. 1 filetype = output_config[:filetype]
  113. 1 file = Tempfile.new [id.to_s, ".#{filetype}"]
  114. 1 file.write output
  115. 1 file.rewind
  116. 1 Card::Auth.as_bot do
  117. 1 p = machine_output_card
  118. 1 p.file = file
  119. 1 p.save!
  120. end
  121. 1 file.close
  122. 1 file.unlink
  123. end
  124. 1 view :machine_output_url do
  125. machine_output_url
  126. end
  127. 1 class << self
  128. 1 def included host_class
  129. 6 host_class.extend(MachineClassMethods)
  130. 6 host_class.mattr_accessor :output_config
  131. 6 host_class.output_config = { filetype: "txt" }
  132. 6 define_machine_events host_class
  133. end
  134. 1 def define_machine_events host_class
  135. 6 event_suffix = host_class.name.tr ":", "_"
  136. 6 event_name = "reset_machine_output_#{event_suffix}".to_sym
  137. 6 host_class.event event_name, after: :expire_related, changed: :content, on: :save do
  138. reset_machine_output
  139. end
  140. end
  141. end
  142. 1 include_set Abstract::Lock
  143. 1 def run_machine joint="\n"
  144. 1 before_engine
  145. output =
  146. 1 input_item_cards.map do |input_card|
  147. 1 run_engine input_card
  148. end.select(&:present?).join(joint)
  149. 1 after_engine output
  150. end
  151. 1 def direct_machine_input? input_card
  152. 1 !input_card.collection? ||
  153. input_card.respond_to?(:machine_input)
  154. end
  155. 1 def run_engine input_card
  156. 1 return unless direct_machine_input? input_card
  157. 1 if (cached = fetch_cache_card(input_card)) && cached.content?
  158. return cached.content
  159. end
  160. 1 engine(input_from_card(input_card)).tap do |output|
  161. 1 cache_output_part input_card, output
  162. end
  163. end
  164. 1 def input_from_card input_card
  165. 1 if input_card.respond_to? :machine_input
  166. 1 input_card.machine_input
  167. else
  168. input_card.format._render_raw
  169. end
  170. end
  171. 1 def make_machine_output_coded mod=:machines
  172. update_machine_output
  173. Card::Auth.as_bot do
  174. ENV["STORE_CODED_FILES"] = "true"
  175. machine_output_card.update! storage_type: :coded, mod: mod,
  176. codename: machine_output_codename
  177. ENV["STORE_CODED_FILES"] = nil
  178. end
  179. end
  180. 1 def machine_output_codename
  181. machine_output_card.name.parts.map do |part|
  182. Card[part].codename&.to_s || Card[part].name.safe_key
  183. end.join "_"
  184. end
  185. 1 def input_item_cards
  186. 1 machine_input_card.item_cards
  187. end
  188. 1 def machine_output_url
  189. 94 ensure_machine_output
  190. 94 machine_output_card.file.url # (:default, timestamp: false)
  191. # to get rid of additional number in url
  192. end
  193. 1 def machine_output_path
  194. ensure_machine_output
  195. machine_output_card.file.path
  196. end
  197. end;end;end;end;
  198. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/abstract/machine.rb ~~

card/tmpsets/set/mod007-card-mod-machines/abstract/machine/output_cache.rb

100.0% lines covered

12 relevant lines. 12 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Abstract; module Machine;
  3. # Set: Abstract (Machine, OutputCache)
  4. #
  5. 1 module OutputCache;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/abstract/machine/output_cache.rb"; end
  8. 1 def fetch_cache_card input_card, new=nil
  9. 2 new &&= { type_id: PlainTextID }
  10. 2 Card.fetch input_card.name, name, :machine_cache, new: new
  11. end
  12. 1 def cache_output_part input_card, output
  13. 1 Auth.as_bot do
  14. # save virtual cards first
  15. # otherwise the cache card will save it to get the left_id
  16. # and trigger the cache update again
  17. 1 input_card.save! if input_card.new_card?
  18. 1 cache_card = fetch_cache_card(input_card, true)
  19. 1 cache_card.update! content: output
  20. end
  21. end
  22. end;end;end;end;end;
  23. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/abstract/machine/output_cache.rb ~~

card/tmpsets/set/mod007-card-mod-machines/abstract/machine/output_update.rb

82.98% lines covered

47 relevant lines. 39 lines covered and 8 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Abstract; module Machine;
  3. # Set: Abstract (Machine, OutputUpdate)
  4. #
  5. 1 module OutputUpdate;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/abstract/machine/output_update.rb"; end
  8. 1 def reset_machine_output
  9. 1 Auth.as_bot do
  10. 1 moc = machine_output_card
  11. 1 @updated_at = output_updated_at
  12. 1 moc.delete! if moc.real?
  13. 1 update_input_card
  14. 1 expire_if_source_file_changed @updated_at
  15. end
  16. end
  17. 1 def regenerate_machine_output
  18. return unless ok?(:read)
  19. lock { run_machine }
  20. end
  21. 1 def update_machine_output
  22. 1 return unless ok?(:read)
  23. 1 lock do
  24. 1 update_input_card
  25. 1 expire_if_source_file_changed output_updated_at
  26. 1 run_machine
  27. end
  28. end
  29. 1 def ensure_machine_output
  30. 94 output = fetch :machine_output
  31. 94 return if output&.selected_content_action_id
  32. update_machine_output
  33. end
  34. 1 def update_input_card
  35. 2 if Card::Director.running_act?
  36. input_card = attach_subcard! machine_input_card
  37. input_card.content = ""
  38. engine_input.each { |input| input_card << input }
  39. else
  40. 2 machine_input_card.items = engine_input
  41. end
  42. end
  43. 1 def input_cards_with_changed_source output_updated
  44. 1 machine_input_card.extended_item_cards.select do |i_card|
  45. 1 i_card.try(:source_changed?, since: output_updated)
  46. end
  47. end
  48. 1 def expire_if_source_file_changed output_updated_at
  49. 2 return unless output_updated_at
  50. 1 changed = input_cards_with_changed_source(output_updated_at)
  51. 1 return if changed.empty?
  52. 1 changed.each(&:expire_machine_cache)
  53. 1 true
  54. end
  55. # regenerates the machine output if a source file of a input card has been changed
  56. 1 def update_if_source_file_changed
  57. return unless expire_if_source_file_changed output_updated_at
  58. regenerate_machine_output
  59. end
  60. 1 def output_updated_at
  61. 2 return unless (output_card = machine_output_card)
  62. 2 if output_card.coded?
  63. 1 File.mtime output_card.file.path
  64. else
  65. 1 output_card.updated_at
  66. end
  67. end
  68. end;end;end;end;end;
  69. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/abstract/machine/output_update.rb ~~

card/tmpsets/set/mod007-card-mod-machines/abstract/machine_input.rb

68.29% lines covered

41 relevant lines. 28 lines covered and 13 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (MachineInput)
  4. #
  5. 1 module MachineInput;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/abstract/machine_input.rb"; end
  8. 1 module MachineInputClassMethods
  9. 1 attr_accessor :machines_cql
  10. 1 def machine_input_for args
  11. @machines_cql = args
  12. end
  13. 1 def machine_input &block
  14. 7 define_method :machine_input, block
  15. end
  16. end
  17. 1 def self.included host_class
  18. 4 host_class.extend(MachineInputClassMethods)
  19. 4 host_class.machines_cql = {}
  20. 4 host_class.machine_input do
  21. format._render_raw
  22. end
  23. 4 event_suffix = host_class.name.tr ":", "_"
  24. 4 define_update_event event_suffix, host_class
  25. 4 define_delete_events event_suffix, host_class
  26. end
  27. 1 def self.define_delete_events event_suffix, host_class
  28. 4 event_name = "before_machine_input_deleted_#{event_suffix}".to_sym
  29. 4 host_class.event event_name, :store, on: :delete do
  30. # exclude self because it's on the way to the trash
  31. # otherwise it will be created again with the reset_machine_output
  32. # call in the event below
  33. @involved_machines =
  34. MachineInput.search_involved_machines(name, host_class)
  35. .reject { |card| card == self }
  36. end
  37. 4 event_name = "after_machine_input_deleted_#{event_suffix}".to_sym
  38. 4 host_class.event event_name, :finalize, on: :delete do
  39. expire_machine_cache
  40. @involved_machines.each do |item|
  41. item.reset_machine_output if item.is_a? Machine
  42. end
  43. end
  44. end
  45. 1 def self.define_update_event event_suffix, host_class
  46. 4 host_class.event(
  47. "after_machine_input_updated_#{event_suffix}".to_sym, :integrate,
  48. on: :save
  49. ) do
  50. expire_machine_cache
  51. MachineInput.search_involved_machines(name, host_class)
  52. .each do |item|
  53. item.reset_machine_output if item.is_a? Machine
  54. end
  55. end
  56. end
  57. 1 def self.search_involved_machines name, host_class
  58. cql_statement =
  59. { right_plus: [
  60. { codename: "machine_input" },
  61. { link_to: name }
  62. ] }.merge(host_class.machines_cql)
  63. Card.search(cql_statement)
  64. end
  65. 1 def expire_machine_cache
  66. 1 Card.search(right_plus: [{ codename: "machine_input" }, { link_to: name }],
  67. return: :name).each do |machine_name|
  68. 1 cache_card = Card.fetch(name, machine_name, :machine_cache)
  69. 1 next unless cache_card&.content?
  70. Auth.as_bot { cache_card.update! trash: true }
  71. end
  72. end
  73. end;end;end;end;
  74. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/abstract/machine_input.rb ~~

card/tmpsets/set/mod007-card-mod-machines/abstract/script.rb

56.82% lines covered

44 relevant lines. 25 lines covered and 19 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (Script)
  4. #
  5. # -*- encoding : utf-8 -*-
  6. 1 module Script;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/abstract/script.rb"; end
  9. 1 require "uglifier"
  10. 1 def self.included host_class
  11. 2 host_class.include_set Abstract::Machine
  12. 2 host_class.include_set Abstract::MachineInput
  13. 2 host_class.machine_input { standard_machine_input }
  14. 2 host_class.store_machine_output filetype: "js"
  15. end
  16. 1 def standard_machine_input
  17. js = format(:js)._render_core
  18. js = compress_js js if compress_js?
  19. comment_with_source js
  20. end
  21. 1 def comment_with_source js
  22. "//#{name}\n#{js}"
  23. end
  24. 1 def compress_js input
  25. Uglifier.compile input
  26. rescue => e
  27. # CoffeeScript is compiled in a view
  28. # If there is a CoffeeScript syntax error we get the rescued view here
  29. # and the error that the rescued view is no valid Javascript
  30. # To get the original error we have to refer to Card::Error.current
  31. raise Card::Error, compression_error_message(e)
  32. end
  33. 1 def compression_error_message e
  34. if Card::Error.current
  35. Card::Error.current.message
  36. else
  37. "JavaScript::SyntaxError (#{name}): #{e.message}"
  38. end
  39. end
  40. 1 def compress_js?
  41. Cardio.config.compress_javascript
  42. end
  43. 1 def clean_html?
  44. false
  45. end
  46. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  47. 1 def chunk_list # turn off autodetection of uri's
  48. :nest_only
  49. end
  50. # def default_nest_view
  51. # :raw
  52. # end
  53. end
  54. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  55. 1 def input_type
  56. :ace_editor
  57. end
  58. 1 def ace_mode
  59. :javascript
  60. end
  61. 1 def content_changes action, diff_type, hide_diff=false
  62. wrap_with(:pre) { super }
  63. end
  64. 1 view :core do
  65. script = card.format(:js).render_core
  66. process_content highlight(script)
  67. end
  68. 1 def highlight script
  69. ::CodeRay.scan(script, :js).div
  70. end
  71. end
  72. 1 def diff_args
  73. { diff_format: :text }
  74. end
  75. end;end;end;end;
  76. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/abstract/script.rb ~~

card/tmpsets/set/mod007-card-mod-machines/abstract/skin_box.rb

52.38% lines covered

21 relevant lines. 11 lines covered and 10 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (SkinBox)
  4. #
  5. 1 module SkinBox;
  6. 1 extend Card::Set
  7. 2 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/abstract/skin_box.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :box do
  10. class_up "box-middle", "p-0"
  11. voo.hide :customize_button, :box_middle
  12. super()
  13. end
  14. 1 view :box_bottom, template: :haml
  15. 1 view :customize_button, cache: :never do
  16. customize_button
  17. end
  18. 1 def customize_button target: parent&.card, text: "Apply and customize"
  19. return "" unless card.codename.present?
  20. theme = card.codename.match(/^(?<theme_name>.+)_skin$/).capture(:theme_name)
  21. link_to_card target, text,
  22. path: { action: :update, card: { content: "[[#{card.name}]]" },
  23. customize: true, theme: theme },
  24. class: "btn btn-sm btn-outline-primary mr-2"
  25. end
  26. 1 view :box_middle do
  27. return unless card.field(:image)
  28. field_nest(:image, view: :full_width, size: :large)
  29. end
  30. 1 def select_button target=parent.card
  31. link_to_card target, "Apply",
  32. path: { action: :update, card: { content: "[[#{card.name}]]" } },
  33. class: "btn btn-sm btn-primary"
  34. end
  35. end
  36. end;end;end;end;
  37. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/abstract/skin_box.rb ~~

card/tmpsets/set/mod007-card-mod-machines/all/reset_machines.rb

38.89% lines covered

18 relevant lines. 7 lines covered and 11 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (ResetMachines)
  4. #
  5. 1 module ResetMachines;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/all/reset_machines.rb"; end
  8. 1 module ClassMethods
  9. 1 def reset_script_machine
  10. Auth.as_bot do
  11. card = Card[:all, :script, :machine_output]
  12. if card
  13. card.update_columns trash: true
  14. card.expire
  15. Card::Virtual.where(right_id: MachineCacheID).delete_all
  16. end
  17. end
  18. end
  19. 1 def reset_all_machines
  20. Auth.as_bot do
  21. Card.search(right: { codename: "machine_output" }).each do |card|
  22. card.update_columns trash: true
  23. card.expire
  24. end
  25. Card::Virtual.where(right_id: MachineCacheID).delete_all
  26. end
  27. end
  28. end
  29. end;end;end;end;
  30. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/all/reset_machines.rb ~~

card/tmpsets/set/mod007-card-mod-machines/right/machine_cache.rb

85.71% lines covered

7 relevant lines. 6 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+MachineCache" cards
  4. #
  5. 1 module MachineCache;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/right/machine_cache.rb"; end
  8. 1 include_set Abstract::VirtualCache
  9. 1 def clean_html?
  10. false
  11. end
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/right/machine_cache.rb ~~

card/tmpsets/set/mod007-card-mod-machines/right/machine_input.rb

100.0% lines covered

8 relevant lines. 8 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+MachineInput" cards
  4. #
  5. 1 module MachineInput;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/right/machine_input.rb"; end
  8. 1 def followable?
  9. 1 false
  10. end
  11. 1 def history?
  12. 5 false
  13. end
  14. end;end;end;end;
  15. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/right/machine_input.rb ~~

card/tmpsets/set/mod007-card-mod-machines/right/machine_output.rb

88.89% lines covered

27 relevant lines. 24 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+MachineOutput" cards
  4. #
  5. 1 module MachineOutput;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/right/machine_output.rb"; end
  8. 1 def followable?
  9. 1 false
  10. end
  11. 1 def ok_to_read
  12. 2 left.ok_to_read
  13. end
  14. 1 def history?
  15. 5 false
  16. end
  17. 1 event :remove_codename, :prepare_to_validate,
  18. on: :delete,
  19. 1 when: proc { |c| c.codename.present? } do
  20. # load file before deleting codename otherwise it will fail later
  21. 1 attachment
  22. 1 self.codename = nil
  23. end
  24. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  25. 1 view :not_found do
  26. 1 if update_machine_output_live?
  27. 1 Card::Cache.reset_all # FIXME: wow, this is overkill, no?
  28. 1 root.error_status = 302
  29. 1 card.left.update_machine_output
  30. 1 card_path card.left.machine_output_url
  31. else
  32. super()
  33. end
  34. end
  35. 1 def update_machine_output_live?
  36. case
  37. 1 when !card.left.is_a?(Abstract::Machine) then false # must be a machine
  38. when card.left.locked? then false # machine must not be running
  39. 1 when card.new_card? then true # always update if new
  40. else
  41. # must want current output (won't re-output old stuff)
  42. (selected_id = card.selected_action_id) &&
  43. selected_id == card.last_action_id
  44. end
  45. end
  46. end
  47. end;end;end;end;
  48. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/right/machine_output.rb ~~

card/tmpsets/set/mod007-card-mod-machines/self/script_decko.rb

75.0% lines covered

8 relevant lines. 6 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ScriptDecko"
  4. #
  5. 1 module ScriptDecko;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/self/script_decko.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 def source_files
  10. %w[mod editor name_editor autosave doubleclick layout navbox upload
  11. slot modal overlay recaptcha slotter bridge
  12. nest_editor nest_editor_rules nest_editor_options nest_editor_name
  13. link_editor
  14. components decko follow card_menu slot_ready
  15. filter filter_links filter_items selectable_filtered_content].map do |n|
  16. "decko/#{n}.js.coffee"
  17. end
  18. end
  19. end;end;end;end;
  20. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/self/script_decko.rb ~~

card/tmpsets/set/mod007-card-mod-machines/self/script_html5shiv_printshiv.rb

100.0% lines covered

8 relevant lines. 8 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ScriptHtml5shivPrintshiv"
  4. #
  5. 1 module ScriptHtml5shivPrintshiv;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/self/script_html5shiv_printshiv.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  10. 1 view :script_tag, perms: :none do
  11. 23 <<-HTML.strip_heredoc
  12. <!--[if lt IE 9]>
  13. #{javascript_include_tag card.machine_output_url}
  14. <![endif]-->
  15. HTML
  16. end
  17. end
  18. end;end;end;end;
  19. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/self/script_html5shiv_printshiv.rb ~~

card/tmpsets/set/mod007-card-mod-machines/self/script_jquery.rb

77.78% lines covered

9 relevant lines. 7 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ScriptJquery"
  4. #
  5. 1 module ScriptJquery;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/self/script_jquery.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 def source_files
  10. ["vendor/jquery_rails/vendor/assets/javascripts/jquery3.js",
  11. "vendor/jquery_rails/vendor/assets/javascripts/jquery_ujs.js"]
  12. end
  13. 1 def source_dir
  14. ""
  15. end
  16. end;end;end;end;
  17. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/self/script_jquery.rb ~~

card/tmpsets/set/mod007-card-mod-machines/self/script_jquery_helper.rb

87.5% lines covered

8 relevant lines. 7 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ScriptJqueryHelper"
  4. #
  5. 1 module ScriptJqueryHelper;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/self/script_jquery_helper.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 Self::ScriptLibraries.add_item :script_jquery_helper
  10. 1 def source_files
  11. # jquery-ui includes all interaction components, the dialog and the autocomplete widget
  12. # and all dependencies for those
  13. # decko depends on autocomplete, sortable, jquery.autosize and jquery.fileupload
  14. # the dialog widget is not used in decko but in wikirate
  15. # don't know if iframe-transport is needed but it used to be there
  16. %w[jquery-ui.js
  17. jquery.autosize.js
  18. ../../vendor/jquery_file_upload/js/jquery.fileupload.js
  19. ../../vendor/jquery_file_upload/js/jquery.iframe-transport.js]
  20. end
  21. end;end;end;end;
  22. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/self/script_jquery_helper.rb ~~

card/tmpsets/set/mod007-card-mod-machines/self/style_bootstrap_compatible.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "StyleBootstrapCompatible"
  4. #
  5. 1 module StyleBootstrapCompatible;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/self/style_bootstrap_compatible.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. end;end;end;end;
  10. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/self/style_bootstrap_compatible.rb ~~

card/tmpsets/set/mod007-card-mod-machines/self/style_cards.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "StyleCards"
  4. #
  5. 1 module StyleCards;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/self/style_cards.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. end;end;end;end;
  10. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/self/style_cards.rb ~~

card/tmpsets/set/mod007-card-mod-machines/self/style_jquery_ui_smoothness.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "StyleJqueryUiSmoothness"
  4. #
  5. 1 module StyleJqueryUiSmoothness;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/self/style_jquery_ui_smoothness.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. end;end;end;end;
  10. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/self/style_jquery_ui_smoothness.rb ~~

card/tmpsets/set/mod007-card-mod-machines/type/coffee_script.rb

64.71% lines covered

17 relevant lines. 11 lines covered and 6 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "CoffeeScript" cards
  4. #
  5. # -*- encoding : utf-8 -*-
  6. 1 module CoffeeScript;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/type/coffee_script.rb"; end
  9. 1 require "coffee-script"
  10. 1 include_set Abstract::Script
  11. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  12. 1 def ace_mode
  13. :coffee
  14. end
  15. end
  16. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  17. 1 view :core do
  18. compile_coffee _render_raw
  19. end
  20. 1 def compile_coffee script
  21. ::CoffeeScript.compile script
  22. rescue => e
  23. line_nr = e.to_s.match(/\[stdin\]:(\d*)/)&.capture(0)&.to_i
  24. line = script.lines[line_nr - 1] if line_nr
  25. raise Card::Error, "CoffeeScript::Error (#{card.name}): #{e.message}: #{line}"
  26. end
  27. end
  28. end;end;end;end;
  29. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/type/coffee_script.rb ~~

card/tmpsets/set/mod007-card-mod-machines/type/css.rb

69.05% lines covered

42 relevant lines. 29 lines covered and 13 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Css" cards
  4. #
  5. # -*- encoding : utf-8 -*-
  6. 1 module Css;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/type/css.rb"; end
  9. 1 require "sassc"
  10. 1 require "benchmark"
  11. 1 include_set Abstract::Machine
  12. 1 include_set Abstract::MachineInput
  13. 1 store_machine_output filetype: "css"
  14. 1 machine_input do
  15. 1 compress_css format(format: :css)._render_core
  16. end
  17. 1 def compress_css input
  18. 1 compress_css? ? SassC::Engine.new(input, style: :compressed).render : input
  19. rescue => e
  20. raise Card::Error, css_compression_error(e)
  21. end
  22. 1 def css_compression_error error
  23. # scss is compiled in a view
  24. # If there is a scss syntax error we get the rescued view here
  25. # and the error that the rescued view is no valid css
  26. # To get the original error we have to refer to Card::Error.current
  27. if Card::Error.current
  28. Card::Error.current.message
  29. else
  30. "Sass::SyntaxError (#{name}): #{error.message}"
  31. end
  32. end
  33. 1 def clean_html?
  34. false
  35. end
  36. 1 def compress_css?
  37. 1 return true
  38. !Rails.env.development?
  39. end
  40. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  41. # def default_nest_view
  42. # :raw
  43. # end
  44. 1 def chunk_list # turn off autodetection of uri's
  45. 1 :references
  46. end
  47. end
  48. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  49. 1 def input_type
  50. :ace_editor
  51. end
  52. 1 def ace_mode
  53. :css
  54. end
  55. 1 def default_nest_view
  56. :closed
  57. end
  58. 1 view :core do
  59. # FIXME: scan must happen before process for inclusion interactions to
  60. # work, but this will likely cause
  61. # problems with including other css?
  62. process_content ::CodeRay.scan(_render_raw, :css).div, size: :icon
  63. end
  64. 1 def content_changes action, diff_type, hide_diff=false
  65. wrap_with(:pre) { super }
  66. end
  67. end
  68. 2 module CssFormat; module_parent.send :register_set_format, Card::Format::CssFormat, self; extend Card::Set::AbstractFormat
  69. 1 view :import do
  70. %{\n@import url("#{_render_url}");\n}
  71. end
  72. end
  73. 1 def diff_args
  74. { diff_format: :text }
  75. end
  76. end;end;end;end;
  77. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/type/css.rb ~~

card/tmpsets/set/mod007-card-mod-machines/type/java_script.rb

87.5% lines covered

8 relevant lines. 7 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "JavaScript" cards
  4. #
  5. # -*- encoding : utf-8 -*-
  6. 1 module JavaScript;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/type/java_script.rb"; end
  9. 1 include_set Abstract::Script
  10. 2 module JsFormat; module_parent.send :register_set_format, Card::Format::JsFormat, self; extend Card::Set::AbstractFormat
  11. 1 view :core do
  12. _render_raw
  13. end
  14. end
  15. end;end;end;end;
  16. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/type/java_script.rb ~~

card/tmpsets/set/mod007-card-mod-machines/type/scss.rb

85.71% lines covered

14 relevant lines. 12 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Scss" cards
  4. #
  5. 1 module Scss;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/type/scss.rb"; end
  8. 1 include_set Type::Css
  9. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  10. 1 view :core, cache: :never do
  11. 1 compile_scss(process_content(_render_raw))
  12. end
  13. 1 def compile_scss scss, style=:expanded
  14. 1 SassC::Engine.new(scss, style: style).render
  15. rescue SassC::SyntaxError => e
  16. raise Card::Error,
  17. "SassC::SyntaxError (#{card.name}:#{e.sass_backtrace}): #{e.message}"
  18. # "#{#scss.lines[e.sass_line - 1]}\n" \
  19. end
  20. end
  21. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  22. 1 def ace_mode
  23. :scss
  24. end
  25. end
  26. end;end;end;end;
  27. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/type/scss.rb ~~

card/tmpsets/set/mod007-card-mod-machines/type/skin.rb

88.89% lines covered

9 relevant lines. 8 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Skin" cards
  4. #
  5. 1 module Skin;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-machines/set/type/skin.rb"; end
  8. 1 include_set Abstract::MachineInput
  9. 1 include_set Abstract::SkinBox
  10. 1 include_set Pointer
  11. 1 def machine_input
  12. # only the item of a skin card contribute input to the machine
  13. # not the skin card itself
  14. ""
  15. end
  16. end;end;end;end;
  17. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-machines/set/type/skin.rb ~~

card/tmpsets/set/mod008-settings/abstract/permission.rb

37.93% lines covered

58 relevant lines. 22 lines covered and 36 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (Permission)
  4. #
  5. 1 module Permission;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/abstract/permission.rb"; end
  8. 1 def standardize_items
  9. 4 super unless content == "_left"
  10. end
  11. 1 def options_rule_card
  12. 1301 Card[:cards_with_account]
  13. end
  14. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  15. 1 view :pointer_core do
  16. wrap_with :div, pointer_items, class: "pointer-list"
  17. end
  18. 1 view :core, cache: :never do
  19. if card.content == "_left"
  20. core_inherit_content
  21. else
  22. render! :pointer_core
  23. end
  24. end
  25. 1 view :one_line_content, cache: :never do
  26. render_core items: { view: :link }
  27. end
  28. 1 view :input do
  29. item_names = inheriting? ? [] : card.item_names
  30. %(
  31. #{_render_hidden_content_field}
  32. <div class="perm-editor">
  33. #{inheritance_checkbox}
  34. <div class="perm-group perm-vals perm-section">
  35. <h5 class="text-muted">Groups</h5>
  36. #{groups item_names}
  37. </div>
  38. <div class="perm-indiv perm-vals perm-section">
  39. <h5 class="text-muted">Individuals</h5>
  40. #{list_input item_list: item_names, extra_css_class: 'perm-indiv-ul'}
  41. </div>
  42. </div>
  43. )
  44. end
  45. 1 private
  46. 1 def groups item_names
  47. group_options.map do |option|
  48. checked = !item_names.delete(option.name).nil?
  49. icon = icon_tag "open_in_new", "link-muted"
  50. option_link = link_to_card option.name, icon, target: "decko_role"
  51. box = check_box_tag "#{option.key}-perm-checkbox",
  52. option.name, checked, class: "perm-checkbox-button"
  53. <<-HTML
  54. <div class="form-check checkbox">
  55. <label class="form-check-label">
  56. #{box} #{option.name} #{option_link}
  57. </label>
  58. </div>
  59. HTML
  60. end * "\n"
  61. end
  62. 1 def group_options
  63. Auth.as_bot do
  64. Card.search({ type_id: RoleID, sort: "name" }, "roles by name")
  65. end
  66. end
  67. 1 def inheritable?
  68. @inheritable ||=
  69. begin
  70. set_name = card.name.trunk_name
  71. set_card = Card.fetch(set_name)
  72. not_set = set_card && set_card.type_id != SetID
  73. not_set ? false : set_card.inheritable?
  74. end
  75. end
  76. 1 def inheriting?
  77. @inheriting ||= inheritable? && card.content == "_left"
  78. end
  79. 1 def inheritance_checkbox
  80. return unless inheritable?
  81. <<-HTML
  82. <div class="perm-inheritance perm-section">
  83. #{check_box_tag 'inherit', 'inherit', inheriting?}
  84. <label>
  85. #{core_inherit_content}
  86. #{wrap_with(:a, title: "use left's #{card.name.tag} rule") { '?' }}
  87. </label>
  88. </div>
  89. HTML
  90. end
  91. 1 def core_inherit_content
  92. text = if in_context_of_self_set?
  93. core_inherit_for_content_for_self_set
  94. else
  95. "Inherit from left card"
  96. end
  97. %(<span class="inherit-perm">#{text}</span>)
  98. end
  99. 1 def in_context_of_self_set?
  100. return false unless @set_context
  101. @set_context.to_name.tag_name.key == Card[:self].key
  102. end
  103. 1 def core_inherit_for_content_for_self_set
  104. task = card.tag.codename
  105. ancestor = Card[@set_context.trunk_name.trunk_name]
  106. links = ancestor.who_can(task).map do |card_id|
  107. link_to_card card_id, nil, target: args[:target]
  108. end * ", "
  109. "Inherit ( #{links} )"
  110. rescue
  111. "Inherit"
  112. end
  113. end
  114. end;end;end;end;
  115. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/abstract/permission.rb ~~

card/tmpsets/set/mod008-settings/abstract/templated_nests.rb

75.0% lines covered

8 relevant lines. 6 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (TemplatedNests)
  4. #
  5. 1 module TemplatedNests;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/abstract/templated_nests.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :core do
  10. with_nest_mode :template do
  11. super()
  12. end
  13. end
  14. end
  15. end;end;end;end;
  16. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/abstract/templated_nests.rb ~~

card/tmpsets/set/mod008-settings/all/supports_content_options.rb

75.0% lines covered

8 relevant lines. 6 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (SupportsContentOptions)
  4. #
  5. 1 module SupportsContentOptions;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/all/supports_content_options.rb"; end
  8. 1 def supports_content_options?
  9. false
  10. end
  11. 1 def supports_content_option_view?
  12. false
  13. end
  14. end;end;end;end;
  15. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/all/supports_content_options.rb ~~

card/tmpsets/set/mod008-settings/right/autoname.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Autoname" cards
  4. #
  5. 1 module Autoname;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/autoname.rb"; end
  8. 1 def history?
  9. 2 false
  10. end
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/autoname.rb ~~

card/tmpsets/set/mod008-settings/right/comment.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Comment" cards
  4. #
  5. 1 module Comment;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/comment.rb"; end
  8. 1 include_set Abstract::Permission
  9. end;end;end;end;
  10. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/comment.rb ~~

card/tmpsets/set/mod008-settings/right/content_option_view.rb

66.67% lines covered

9 relevant lines. 6 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+ContentOptionView" cards
  4. #
  5. 1 module ContentOptionView;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/content_option_view.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def quick_edit
  10. if card.left.prototype_default_card&.try(:show_content_options?) &&
  11. card.left.prototype.rule_card(:input_type)&.supports_content_option_view?
  12. super
  13. else
  14. ""
  15. end
  16. end
  17. end
  18. end;end;end;end;
  19. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/content_option_view.rb ~~

card/tmpsets/set/mod008-settings/right/content_options.rb

61.54% lines covered

13 relevant lines. 8 lines covered and 5 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+ContentOptions" cards
  4. #
  5. 1 module ContentOptions;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/content_options.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def quick_edit
  10. card.left.prototype_default_card.try(:show_content_options?) ? super : ""
  11. end
  12. 1 def quick_editor
  13. wrap_type_formgroup do
  14. type_field class: "type-field rule-type-field _submit-on-select"
  15. end +
  16. wrap_content_formgroup do
  17. text_field :content, class: "d0-card-content _submit-after-typing"
  18. end
  19. end
  20. 1 def visible_cardtype_groups
  21. { "Organize" => %w[List Pointer] }
  22. end
  23. end
  24. end;end;end;end;
  25. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/content_options.rb ~~

card/tmpsets/set/mod008-settings/right/create.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Create" cards
  4. #
  5. 1 module Create;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/create.rb"; end
  8. 1 include_set Abstract::Permission
  9. end;end;end;end;
  10. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/create.rb ~~

card/tmpsets/set/mod008-settings/right/default.rb

52.38% lines covered

21 relevant lines. 11 lines covered and 10 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Default" cards
  4. #
  5. 1 module Default;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/default.rb"; end
  8. 1 include_set Abstract::TemplatedNests
  9. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  10. 1 view :one_line_content do
  11. raw = _render_raw
  12. "#{card.type_name} : #{raw.present? ? raw : '<em>empty</em>'}"
  13. end
  14. 1 def quick_form_opts
  15. super.merge "data-update-foreign-slot":
  16. ".card-slot.quick_edit-view.RIGHT-Xinput_type,"\
  17. ".card-slot.quick_edit-view.RIGHT-Xcontent_option"\
  18. ".card-slot.quick_edit-view.RIGHT-Xcontent_option_view"
  19. end
  20. 1 def quick_editor
  21. wrap_type_formgroup do
  22. type_field class: "type-field rule-type-field _submit-on-select"
  23. end +
  24. wrap_content_formgroup do
  25. text_field :content, class: "d0-card-content _submit-after-typing"
  26. end
  27. end
  28. 1 def visible_cardtype_groups
  29. hash = ::Card::Set::Self::Cardtype::GROUP.slice("Text", "Data", "Upload")
  30. hash["Organize"] = ["List", "Pointer", "Link list", "Nest list"]
  31. hash
  32. end
  33. end
  34. 1 def empty_ok?
  35. true
  36. end
  37. end;end;end;end;
  38. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/default.rb ~~

card/tmpsets/set/mod008-settings/right/delete.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Delete" cards
  4. #
  5. 1 module Delete;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/delete.rb"; end
  8. 1 include_set Abstract::Permission
  9. end;end;end;end;
  10. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/delete.rb ~~

card/tmpsets/set/mod008-settings/right/guide.rb

85.71% lines covered

7 relevant lines. 6 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Guide" cards
  4. #
  5. # include_set Abstract::TemplatedNests
  6. 1 module Guide;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/guide.rb"; end
  9. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  10. 1 def raw_help_text
  11. # LOCALIZE
  12. "Appears in the full editor view to guide users."
  13. end
  14. end
  15. end;end;end;end;
  16. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/guide.rb ~~

card/tmpsets/set/mod008-settings/right/help.rb

72.73% lines covered

11 relevant lines. 8 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Help" cards
  4. #
  5. 1 module Help;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/help.rb"; end
  8. 1 include_set Abstract::TemplatedNests
  9. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  10. 1 view :popover do
  11. popover_link _render_core
  12. end
  13. 1 def quick_editor
  14. # TODO: refactor when voo.input_type is ready. (and use class_up)
  15. formgroup "Content", input: :content, help: false do
  16. text_field :content, value: card.content,
  17. class: "d0-card-content _submit-after-typing"
  18. end
  19. end
  20. end
  21. end;end;end;end;
  22. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/help.rb ~~

card/tmpsets/set/mod008-settings/right/input_type.rb

60.0% lines covered

20 relevant lines. 12 lines covered and 8 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+InputType" cards
  4. #
  5. 1 module InputType;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/input_type.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def quick_editor
  10. @submit_on_change = true
  11. super
  12. end
  13. 1 def quick_form_opts
  14. super.merge "data-update-foreign-slot":
  15. ".card-slot.quick_edit-view.RIGHT-Xcontent_option_view"
  16. end
  17. 1 def default_input_type
  18. :radio
  19. end
  20. 1 def raw_help_text
  21. "edit interface for list cards"
  22. end
  23. # def option_label_text option_name
  24. # super.downcase
  25. # end
  26. 1 def quick_edit
  27. card.left.prototype_default_card.try(:show_input_type?) ? super : ""
  28. end
  29. end
  30. 1 def option_names
  31. left.prototype_default_card&.try(:input_type_content_options) || super
  32. end
  33. 1 def supports_content_option_view?
  34. item_name.in? ["checkbox", "radio", "filtered list"]
  35. end
  36. end;end;end;end;
  37. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/input_type.rb ~~

card/tmpsets/set/mod008-settings/right/read.rb

97.73% lines covered

44 relevant lines. 43 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Read" cards
  4. #
  5. 1 module Read;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/read.rb"; end
  8. 1 include Abstract::Permission
  9. 2 format :html do include Abstract::Permission::HtmlFormat end
  10. 1 event :cascade_read_rule, :finalize, after: :update_rule_cache, when: :is_rule? do
  11. 2 return unless name_is_changing? || trash_is_changing?
  12. 2 update_read_ruled_cards
  13. end
  14. 1 def update_read_ruled_cards
  15. 2 Card::Rule.clear_read_rule_cache
  16. 2 Card.cache.reset # maybe be more surgical, just Auth.user related
  17. 2 expire # probably shouldn't be necessary,
  18. # but was sometimes getting cached version when card should be in the
  19. # trash. could be related to other bugs?
  20. 2 processed = update_read_rules_of_set_members
  21. 2 update_cards_with_read_rule_id processed unless new?
  22. end
  23. 1 def update_read_rules_of_set_members
  24. 2 return unless rule_pattern_index
  25. 2 each_member do |member, processed|
  26. 2 processed << member.key
  27. 2 member.update_read_rule unless member_has_overriding_rule?(member)
  28. end
  29. end
  30. 1 def member_has_overriding_rule? member
  31. 2 pattern_index(Card.fetch_id(member.read_rule_class)) < rule_pattern_index
  32. end
  33. # cards with this card as a read_rule_id
  34. # These may include cards that are no longer set members if the card was renamed
  35. # (edge case)
  36. 1 def update_cards_with_read_rule_id processed
  37. 2 processed ||= ::Set.new
  38. 2 Card::Auth.as_bot do
  39. 2 Card.search(read_rule_id: id) do |card|
  40. 6 card.update_read_rule unless processed.include?(card.key)
  41. end
  42. end
  43. end
  44. 1 def each_member
  45. 2 Auth.as_bot do
  46. 2 all_members.each_with_object(::Set.new) do |member, processed|
  47. 2 yield member, processed
  48. end
  49. end
  50. end
  51. 1 def all_members
  52. 2 rule_set.item_cards limit: 0
  53. end
  54. 1 def rule_pattern_index
  55. 4 return if trash
  56. 4 @rule_pattern_index ||= pattern_index rule_set&.tag&.id
  57. end
  58. 1 def pattern_index pattern_id
  59. 4 pattern_ids.index(pattern_id) || invalid_pattern_id(pattern_id)
  60. end
  61. 1 def pattern_ids
  62. 4 @pattern_ids ||= set_patterns.map(&:pattern_id)
  63. end
  64. 1 def invalid_pattern_id pattern_id
  65. Rails.logger.info "invalid pattern id for read rule: #{pattern_id}"
  66. end
  67. 1 event :process_read_rule_update_queue, :finalize do
  68. 11 left&.update_read_rule
  69. end
  70. end;end;end;end;
  71. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/read.rb ~~

card/tmpsets/set/mod008-settings/right/script.rb

84.62% lines covered

13 relevant lines. 11 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Script" cards
  4. #
  5. 1 module Script;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/script.rb"; end
  8. 1 include_set Abstract::Machine
  9. 1 store_machine_output filetype: "js"
  10. 1 def ok_to_read
  11. 1 true
  12. end
  13. 1 view :javascript_include_tag do
  14. %(
  15. <script src="#{card.machine_output_url}" type="text/javascript"></script>
  16. )
  17. end
  18. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  19. 1 def raw_help_text
  20. "JavaScript (or CoffeeScript) for card's page."
  21. end
  22. end
  23. end;end;end;end;
  24. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/script.rb ~~

card/tmpsets/set/mod008-settings/right/structure.rb

42.5% lines covered

40 relevant lines. 17 lines covered and 23 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Structure" cards
  4. #
  5. 1 module Structure;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/structure.rb"; end
  8. 1 include_set Abstract::TemplatedNests
  9. 2 module RssFormat; module_parent.send :register_set_format, Card::Format::RssFormat, self; extend Card::Set::AbstractFormat
  10. 1 def raw_feed_items
  11. [card]
  12. end
  13. end
  14. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  15. 1 view :one_line_content do
  16. "#{_render_type} : #{_render_raw}"
  17. end
  18. 1 def visible_cardtype_groups
  19. hash = ::Card::Set::Self::Cardtype::GROUP.slice("Text")
  20. hash["Organize"] = ["Search", "Nest list"]
  21. hash
  22. end
  23. end
  24. 1 event :update_structurees_references, :integrate,
  25. when: :update_structurees_references? do
  26. return unless (query = structuree_query)
  27. Auth.as_bot do
  28. query.run.each(&:update_references_out)
  29. end
  30. end
  31. 1 def update_structurees_references?
  32. db_content_changed? || action == :delete
  33. end
  34. 1 event :reset_cache_to_use_new_structure,
  35. before: :update_structurees_references do
  36. Card::Cache.reset_hard
  37. Card::Cache.reset_soft
  38. end
  39. 1 event :update_structurees_type, :finalize,
  40. changed: :type_id, when: proc { |c| c.assigns_type? } do
  41. update_structurees type_id: type_id
  42. end
  43. 1 def structuree_names
  44. return [] unless (query = structuree_query(return: :name))
  45. Auth.as_bot do
  46. query.run
  47. end
  48. end
  49. 1 def update_structurees args
  50. # note that this is not smart about overriding templating rules
  51. # for example, if someone were to change the type of a
  52. # +*right+*structure rule that was overridden
  53. # by a +*type plus right+*structure rule, the override would not be respected.
  54. return unless (query = structuree_query(return: :id))
  55. Auth.as_bot do
  56. query.run.each_slice(100) do |id_batch|
  57. Card.where(id: id_batch).update_all args
  58. end
  59. end
  60. end
  61. 1 def structuree_query args={}
  62. set_card = trunk
  63. return unless set_card.type_id == SetID
  64. set_card.fetch_query args
  65. end
  66. end;end;end;end;
  67. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/structure.rb ~~

card/tmpsets/set/mod008-settings/right/style.rb

58.82% lines covered

34 relevant lines. 20 lines covered and 14 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Style" cards
  4. #
  5. 1 module Style;
  6. 1 extend Card::Set
  7. 2 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/style.rb"; end
  8. 1 require "sassc"
  9. 1 include_set Abstract::Machine
  10. 1 store_machine_output filetype: "css"
  11. 1 def ok_to_read
  12. 25 true
  13. end
  14. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  15. # turn off autodetection of uri's
  16. 1 def chunk_list
  17. :nest_only
  18. end
  19. end
  20. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  21. 1 HIDDEN_SKINS = %w[bootstrap_default_skin themeless_bootstrap_skin bootstrap_default_skin
  22. classic_bootstrap_skin].freeze
  23. 1 def default_item_view
  24. :bar
  25. end
  26. 1 view :input, template: :haml
  27. 1 def themes
  28. card.rule_card(:content_options).item_cards
  29. end
  30. 1 def selectable_themes
  31. themes.reject do |theme_card|
  32. theme_card.right&.codename == :stylesheets ||
  33. theme_card.key.in?(HIDDEN_SKINS)
  34. end
  35. end
  36. end
  37. 1 event :customize_theme, :prepare_to_validate, on: :update, when: :customize_theme? do
  38. skin_name = free_skin_name
  39. add_subcard skin_name, type_id: CustomizedBootswatchSkinID
  40. self.content = "[[#{skin_name}]]"
  41. end
  42. 1 def free_skin_name
  43. name = "#{@theme} skin customized"
  44. if Card.exist?(name)
  45. name = "#{name} 1"
  46. name.next! while Card.exist?(name)
  47. end
  48. name
  49. end
  50. 1 def customize_theme?
  51. Env.params[:customize].present? && (@theme = Env.params[:theme]).present?
  52. end
  53. end;end;end;end;
  54. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/style.rb ~~

card/tmpsets/set/mod008-settings/right/update.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Update" cards
  4. #
  5. 1 module Update;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/update.rb"; end
  8. 1 include_set Abstract::Permission
  9. end;end;end;end;
  10. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/right/update.rb ~~

card/tmpsets/set/mod008-settings/self/autoname.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Autoname"
  4. #
  5. 1 module Autoname;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/autoname.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :templating, position: 4,
  10. help_text: "Autogenerate name for new cards by incrementing this value. "\
  11. "[[http://decko.org/autonaming|more]]"
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/autoname.rb ~~

card/tmpsets/set/mod008-settings/self/captcha.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Captcha"
  4. #
  5. 1 module Captcha;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/captcha.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :permission, position: 5,
  10. help_text: "Anti-spam setting. Requires non-signed-in users to complete a "\
  11. "[[http://decko.org/captcha|captcha]] before adding or editing "\
  12. "cards (where permitted)."
  13. end;end;end;end;
  14. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/captcha.rb ~~

card/tmpsets/set/mod008-settings/self/content_option_view.rb

85.71% lines covered

7 relevant lines. 6 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ContentOptionView"
  4. #
  5. 1 module ContentOptionView;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/content_option_view.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :editing, position: 6,
  10. restricted_to_type: %i[list pointer session],
  11. rule_type_editable: false,
  12. help_text: "Label view for radio button and checkbox items. "\
  13. "[[http://decko.org/Pointer|more]]",
  14. applies: lambda { |prototype|
  15. prototype.supports_content_options? &&
  16. prototype.rule_card(:input_type)&.supports_content_option_view?
  17. }
  18. end;end;end;end;
  19. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/content_option_view.rb ~~

card/tmpsets/set/mod008-settings/self/content_options.rb

85.71% lines covered

7 relevant lines. 6 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ContentOptions"
  4. #
  5. 1 module ContentOptions;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/content_options.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :editing, position: 5,
  10. restricted_to_type: %i[list pointer session],
  11. rule_type_editable: true,
  12. help_text: "Value options for [[List]] and [[Pointer]] and cards. "\
  13. "Can itself be a List or a [[Search]]. "\
  14. "[[http://decko.org/Pointer|more]]",
  15. applies: lambda { |prototype|
  16. prototype.rule_card(:input_type).supports_content_options?
  17. }
  18. end;end;end;end;
  19. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/content_options.rb ~~

card/tmpsets/set/mod008-settings/self/create.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Create"
  4. #
  5. 1 module Create;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/create.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :permission, position: 1, rule_type_editable: false,
  10. short_help_text: "who can create cards",
  11. help_text: "Who can create new cards"
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/create.rb ~~

card/tmpsets/set/mod008-settings/self/csv_structure.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "CsvStructure"
  4. #
  5. 1 module CsvStructure;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/csv_structure.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :templating, position: 3, rule_type_editable: true
  10. end;end;end;end;
  11. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/csv_structure.rb ~~

card/tmpsets/set/mod008-settings/self/default.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Default"
  4. #
  5. 1 module Default;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/default.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :templating, position: 2, rule_type_editable: true,
  10. short_help_text: "type/content template for new cards"
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/default.rb ~~

card/tmpsets/set/mod008-settings/self/default_html_view.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "DefaultHtmlView"
  4. #
  5. 1 module DefaultHtmlView;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/default_html_view.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :other, position: 4, rule_type_editable: false
  10. end;end;end;end;
  11. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/default_html_view.rb ~~

card/tmpsets/set/mod008-settings/self/delete.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Delete"
  4. #
  5. 1 module Delete;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/delete.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :permission, position: 4, rule_type_editable: false,
  10. short_help_text: "who can delete cards",
  11. help_text: "Who can delete cards"
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/delete.rb ~~

card/tmpsets/set/mod008-settings/self/follow_fields.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "FollowFields"
  4. #
  5. 1 module FollowFields;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/follow_fields.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :other, position: 5, rule_type_editable: false
  10. end;end;end;end;
  11. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/follow_fields.rb ~~

card/tmpsets/set/mod008-settings/self/guide.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Guide"
  4. #
  5. 1 module Guide;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/guide.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :editing, position: 3, rule_type_editable: true,
  10. short_help_text: "appears in the full editor view to guide users"
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/guide.rb ~~

card/tmpsets/set/mod008-settings/self/head.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Head"
  4. #
  5. 1 module Head;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/head.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :webpage, position: 1, rule_type_editable: false,
  10. short_help_text: "head tag content",
  11. help_text: "head tag content"
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/head.rb ~~

card/tmpsets/set/mod008-settings/self/help.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Help"
  4. #
  5. 1 module Help;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/help.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :editing, position: 1, rule_type_editable: true,
  10. short_help_text: "help text people will see when editing",
  11. help_text: "[[http://decko.org/custom_help_text|Help text]] "\
  12. "people will see when editing."
  13. end;end;end;end;
  14. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/help.rb ~~

card/tmpsets/set/mod008-settings/self/input_type.rb

88.89% lines covered

9 relevant lines. 8 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "InputType"
  4. #
  5. 1 module InputType;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/input_type.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :editing,
  10. position: 3,
  11. rule_type_editable: false,
  12. short_help_text: "edit interface"
  13. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  14. 1 def raw_help_text
  15. "Configure [[https://ace.c9.io/|ace]], "\
  16. "Decko's default code editor, using these available "\
  17. "[[https://github.com/ajaxorg/ace/wiki/Configuring-Ace|options]]."
  18. end
  19. end
  20. end;end;end;end;
  21. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/input_type.rb ~~

card/tmpsets/set/mod008-settings/self/layout.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Layout"
  4. #
  5. 1 module Layout;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/layout.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :webpage, position: 3, rule_type_editable: false,
  10. help_text: "HTML structure of card's page "\
  11. "[[http://decko.org/layouts | more]]"
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/layout.rb ~~

card/tmpsets/set/mod008-settings/self/on_create.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "OnCreate"
  4. #
  5. 1 module OnCreate;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/on_create.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :event, position: 1, rule_type_editable: false,
  10. help_text: "Configure events to be executed when card is created"
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/on_create.rb ~~

card/tmpsets/set/mod008-settings/self/on_delete.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "OnDelete"
  4. #
  5. 1 module OnDelete;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/on_delete.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :event, position: 3, rule_type_editable: false,
  10. help_text: "Configure events to be executed when card is deleted"
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/on_delete.rb ~~

card/tmpsets/set/mod008-settings/self/on_update.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "OnUpdate"
  4. #
  5. 1 module OnUpdate;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/on_update.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :event, position: 2, rule_type_editable: false,
  10. help_text: "Configure events to be executed when card is updated"
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/on_update.rb ~~

card/tmpsets/set/mod008-settings/self/read.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Read"
  4. #
  5. 1 module Read;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/read.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :permission, position: 2, rule_type_editable: false,
  10. short_help_text: "who can view cards",
  11. help_text: "Who can view cards in the [[set]]."
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/read.rb ~~

card/tmpsets/set/mod008-settings/self/recent_settings.rb

87.5% lines covered

8 relevant lines. 7 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "RecentSettings"
  4. #
  5. 1 module RecentSettings;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/recent_settings.rb"; end
  8. 1 def history?
  9. 30 false
  10. end
  11. 1 def followable?
  12. false
  13. end
  14. end;end;end;end;
  15. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/recent_settings.rb ~~

card/tmpsets/set/mod008-settings/self/script.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Script"
  4. #
  5. 1 module Script;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/script.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :webpage, position: 5
  10. end;end;end;end;
  11. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/script.rb ~~

card/tmpsets/set/mod008-settings/self/structure.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Structure"
  4. #
  5. 1 module Structure;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/structure.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :templating, position: 2, rule_type_editable: true,
  10. short_help_text: "control card's content / structure",
  11. help_text: "Controls cards' content / structure. "\
  12. "[[http://decko.org/formatting|more]]"
  13. end;end;end;end;
  14. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/structure.rb ~~

card/tmpsets/set/mod008-settings/self/style.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Style"
  4. #
  5. 1 module Style;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/style.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :webpage, position: 4,
  10. help_text: "Skin (collection of stylesheets) for card's page. "\
  11. "[[http://decko.org/skins|more]]"
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/style.rb ~~

card/tmpsets/set/mod008-settings/self/table_of_contents.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "TableOfContents"
  4. #
  5. 1 module TableOfContents;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/table_of_contents.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :other, position: 1, rule_type_editable: false,
  10. help_text: "Autogenerate [[http://decko.org/table_of_contents|"\
  11. "table of contents]] on cards with at least this many headers "\
  12. '("0" means never).'
  13. end;end;end;end;
  14. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/table_of_contents.rb ~~

card/tmpsets/set/mod008-settings/self/thanks.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Thanks"
  4. #
  5. 1 module Thanks;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/thanks.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :other, position: 3, rule_type_editable: false,
  10. short_help_text: "destination after card is created",
  11. help_text: "Destination after card is created. "\
  12. "[[http://decko.org/Custom_thank_you_messages_for_forms|more]]"
  13. end;end;end;end;
  14. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/thanks.rb ~~

card/tmpsets/set/mod008-settings/self/update.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Update"
  4. #
  5. 1 module Update;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/update.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :permission, position: 3, rule_type_editable: false,
  10. short_help_text: "who can update cards",
  11. help_text: "Who can update cards"
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/self/update.rb ~~

card/tmpsets/set/mod008-settings/type/setting.rb

48.48% lines covered

33 relevant lines. 16 lines covered and 17 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Setting" cards
  4. #
  5. # require "json"
  6. 1 module Setting;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/settings/set/type/setting.rb"; end
  9. 1 def self.member_names
  10. @@member_names ||= begin
  11. Card.search(
  12. { type_id: SettingID, return: "key" },
  13. "all setting cards"
  14. ).each_with_object({}) do |card_key, hash|
  15. hash[card_key] = true
  16. end
  17. end
  18. end
  19. 2 module DataFormat; module_parent.send :register_set_format, Card::Format::DataFormat, self; extend Card::Set::AbstractFormat
  20. 1 view :core do
  21. cql = { left: { type: SetID },
  22. right: card.id,
  23. limit: 0 }
  24. Card.search(cql).compact.map { |c| nest c }
  25. end
  26. end
  27. 1 def count
  28. Card.search left: { type: SetID }, right: id, limit: 0, return: :count
  29. end
  30. 1 def set_classes_with_rules
  31. Card.set_patterns.reverse.map do |set_class|
  32. cql = { left: { type: SetID },
  33. right: id,
  34. sort: %w[content name],
  35. limit: 0 }
  36. cql[:left][(set_class.anchorless? ? :id : :right_id)] = set_class.pattern_id
  37. rules = Card.search cql
  38. [set_class, rules] unless rules.empty?
  39. end.compact
  40. end
  41. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  42. 1 def rule_link rule, text
  43. link_to_card rule, text, path: { view: :modal_rule },
  44. slotter: true, "data-modal-class": "modal-lg"
  45. end
  46. 1 view :core do
  47. haml do
  48. <<-'HAML'.strip_heredoc
  49. = _render_rule_help
  50. %h3 All #{card.name.tr "*", ""} rules that apply to
  51. - card.set_classes_with_rules.each do |klass, rules|
  52. %p
  53. %h5
  54. = klass.generic_label.downcase
  55. - if klass.anchorless?
  56. = nest rules.first, view: :bar, show: :full_name
  57. - else
  58. - rules.each do |rule|
  59. = nest rule, view: :bar
  60. HAML
  61. end
  62. end
  63. # Because +*help content renders in "template" mode when you render its content
  64. # directly, we render the help text in the context of the *all+<setting> card
  65. 1 view :rule_help do
  66. nest [:all, card.name], view: :rule_help
  67. end
  68. 1 view :one_line_content do
  69. render_rule_help
  70. end
  71. end
  72. 2 module JsonFormat; module_parent.send :register_set_format, Card::Format::JsonFormat, self; extend Card::Set::AbstractFormat
  73. 1 def items_for_export
  74. Card.search left: { type: SetID }, right: card.id, limit: 0
  75. end
  76. end
  77. end;end;end;end;
  78. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/settings/set/type/setting.rb ~~

card/tmpsets/set/mod009-card-mod-search/abstract/00_filter_helper.rb

76.67% lines covered

30 relevant lines. 23 lines covered and 7 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (FilterHelper)
  4. #
  5. # TODO: move sort/filter handling out of card and into base format
  6. 1 module FilterHelper;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/abstract/00_filter_helper.rb"; end
  9. # sorting and filtering is about viewing the data, not altering the data itself.
  10. 1 def sort_hash
  11. 75 sort_param.present? ? { sort: sort_param } : {}
  12. end
  13. 1 def filter_param field
  14. filter_hash[field.to_sym]
  15. end
  16. # FIXME: it is inconsistent that #sort_hash has :sort as the key, but
  17. # #filter_hash is the _value_ of the hash with :filter as the key.
  18. 1 def filter_hash
  19. 75 @filter_hash ||=
  20. 75 Env.params[:filter].present? ? Env.hash(Env.params[:filter]) : default_filter_hash
  21. end
  22. 1 def sort_param
  23. 75 @sort_param ||= safe_sql_param :sort
  24. end
  25. 1 def safe_sql_param key
  26. 75 param = Env.params[key]
  27. 75 param.blank? ? nil : Card::Query.safe_sql(param)
  28. end
  29. 1 def filter_keys_with_values
  30. filter_keys.map do |key|
  31. values = filter_param(key)
  32. values.present? ? [key, values] : next
  33. end.compact
  34. end
  35. # initial values for filtered search
  36. 1 def default_filter_hash
  37. 75 {}
  38. end
  39. 1 def offset
  40. param_to_i :offset, 0
  41. end
  42. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  43. 1 delegate :filter_hash, :sort_hash, :filter_param, :sort_param,
  44. :all_filter_keys, to: :card
  45. 1 def extra_paging_path_args
  46. super.merge filter_and_sort_hash
  47. end
  48. 1 def filter_and_sort_hash
  49. sort_hash.merge filter: filter_hash
  50. end
  51. end
  52. end;end;end;end;
  53. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/abstract/00_filter_helper.rb ~~

card/tmpsets/set/mod009-card-mod-search/abstract/02_search_params.rb

75.76% lines covered

33 relevant lines. 25 lines covered and 8 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (SearchParams)
  4. #
  5. 1 module SearchParams;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/abstract/02_search_params.rb"; end
  8. 1 include_set Abstract::PagingParams
  9. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  10. 1 def offset
  11. search_params[:offset] || 0
  12. end
  13. 1 def search_params
  14. 2 @search_params ||= default_search_params
  15. end
  16. # used for override
  17. 1 def default_search_params
  18. 1 if (qparams = query_params)
  19. paging_params.merge vars: qparams
  20. else
  21. 1 paging_params
  22. end
  23. end
  24. 1 def paging_params
  25. 1 { limit: limit_param, offset: offset_param }
  26. end
  27. 1 def query_params
  28. 1 return nil unless (vars = params[:query])
  29. Env.hash vars
  30. end
  31. 1 def default_limit
  32. 100
  33. end
  34. 1 def extra_paging_path_args
  35. return {} unless (vars = query_params)
  36. { query: vars }
  37. end
  38. end
  39. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  40. 1 def default_limit
  41. 1 Cardio.config.paging_limit || 20
  42. end
  43. end
  44. 2 module JsonFormat; module_parent.send :register_set_format, Card::Format::JsonFormat, self; extend Card::Set::AbstractFormat
  45. 1 def default_limit
  46. 20
  47. end
  48. end
  49. 2 module RssFormat; module_parent.send :register_set_format, Card::Format::RssFormat, self; extend Card::Set::AbstractFormat
  50. 1 def default_limit
  51. 25
  52. end
  53. end
  54. end;end;end;end;
  55. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/abstract/02_search_params.rb ~~

card/tmpsets/set/mod009-card-mod-search/abstract/03_filter.rb

75.0% lines covered

16 relevant lines. 12 lines covered and 4 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (Filter)
  4. #
  5. 1 module Filter;
  6. 1 extend Card::Set
  7. 3 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/abstract/03_filter.rb"; end
  8. 1 include_set Abstract::Utility
  9. 1 def filter_class
  10. Card::FilterQuery
  11. end
  12. 1 def filter_keys
  13. [:name]
  14. end
  15. 1 def filter_keys_from_params
  16. filter_hash.keys.map(&:to_sym) - [:not_ids]
  17. end
  18. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  19. 1 def sort_options
  20. { "Alphabetical": :name, "Recently Added": :create }
  21. end
  22. 1 view :filtered_content, template: :haml, wrap: :slot
  23. 1 view :selectable_filtered_content, template: :haml, cache: :never
  24. end
  25. end;end;end;end;
  26. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/abstract/03_filter.rb ~~

card/tmpsets/set/mod009-card-mod-search/abstract/03_filter/filter_form.rb

44.44% lines covered

45 relevant lines. 20 lines covered and 25 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Abstract; module Filter;
  3. # Set: Abstract (Filter, FilterForm)
  4. #
  5. 1 module FilterForm;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/abstract/03_filter/filter_form.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. # sort and filter ui
  10. 1 view :filter_form, cache: :never do
  11. filter_fields slot_selector: "._filter-result-slot",
  12. sort_field: _render(:sort_formgroup)
  13. end
  14. 1 view :quick_filters, cache: :never do
  15. return "" unless quick_filter_list.present?
  16. haml :quick_filters, filter_list: normalized_quick_filter_list
  17. end
  18. 1 def normalized_quick_filter_list
  19. quick_filter_list.map do |hash|
  20. hash = hash.clone
  21. filter_key = hash.keys.first
  22. {
  23. text: (hash.delete(:text) || hash[filter_key]),
  24. icon: (hash.delete(:icon) || mapped_icon_tag(filter_key)),
  25. # FIXME: mapped_icon_tag is a wikirate concept
  26. class: css_classes(hash.delete(:class),
  27. "_filter-link quick-filter-by-#{filter_key}"),
  28. filter: JSON(hash[:filter] || hash)
  29. }
  30. end
  31. end
  32. # for override
  33. 1 def quick_filter_list
  34. []
  35. end
  36. # for override
  37. 1 def custom_quick_filters
  38. ""
  39. end
  40. # @param data [Hash] the filter categories. The hash needs for every category
  41. # a hash with a label and a input_field entry.
  42. 1 def filter_form data={}, sort_input_field=nil, form_args={}
  43. haml :filter_form, categories: data,
  44. sort_input_field: sort_input_field,
  45. form_args: form_args
  46. end
  47. 1 def filter_fields slot_selector: nil, sort_field: nil
  48. form_args = { action: filter_action_path, class: "slotter" }
  49. form_args["data-slot-selector"] = slot_selector if slot_selector
  50. filter_form filter_form_data, sort_field, form_args
  51. end
  52. 1 def filter_form_data
  53. all_filter_keys.each_with_object({}) do |cat, h|
  54. h[cat] = { label: filter_label(cat),
  55. input_field: _render("filter_#{cat}_formgroup"),
  56. active: active_filter?(cat),
  57. default: default_filter?(cat) }
  58. end
  59. end
  60. 1 def active_filter? field
  61. if card.filter_keys_from_params.present?
  62. filter_hash.key? field
  63. else
  64. default_filter? field
  65. end
  66. end
  67. 1 def default_filter? field
  68. card.default_filter_hash.key? field
  69. end
  70. 1 def filter_label field
  71. # return "Keyword" if field.to_sym == :name
  72. #
  73. filter_label_from_method(field) || filter_label_from_name(field)
  74. end
  75. 1 def filter_label_from_method field
  76. try "#{field}_filter_label"
  77. end
  78. 1 def filter_label_from_name field
  79. Card.fetch_name(field) { field.to_s.titleize }
  80. end
  81. 1 def filter_action_path
  82. path
  83. end
  84. 1 view :sort_formgroup, cache: :never do
  85. select_tag "sort",
  86. options_for_select(sort_options, card.current_sort),
  87. class: "pointer-select _filter-sort form-control",
  88. "data-minimum-results-for-search": "Infinity"
  89. end
  90. end
  91. end;end;end;end;end;
  92. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/abstract/03_filter/filter_form.rb ~~

card/tmpsets/set/mod009-card-mod-search/abstract/03_filter/form_helper.rb

35.94% lines covered

64 relevant lines. 23 lines covered and 41 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Abstract; module Filter;
  3. # Set: Abstract (Filter, FormHelper)
  4. #
  5. 1 module FormHelper;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/abstract/03_filter/form_helper.rb"; end
  8. 1 include_set Abstract::FilterHelper
  9. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  10. 1 view :filter_name_formgroup, cache: :never do
  11. text_filter :name
  12. end
  13. 1 def select_filter field, default=nil, options=nil
  14. options ||= filter_options field
  15. options.unshift(["--", ""]) unless default
  16. select_filter_tag field, default, options
  17. end
  18. 1 def multiselect_filter field, default=nil, options=nil
  19. options ||= filter_options field
  20. multiselect_filter_tag field, default, options
  21. end
  22. 1 def text_filter field, default=nil, opts={}
  23. value = filter_param(field) || default
  24. text_filter_with_name_and_value filter_name(field), value, opts
  25. end
  26. 1 def text_filter_with_name_and_value name, value, opts
  27. opts[:class] ||= "simple-text"
  28. add_class opts, "form-control"
  29. text_field_tag name, value, opts
  30. end
  31. 1 def range_filter field, default={}, opts={}
  32. add_class opts, "simple-text range-filter-subfield"
  33. default ||= {}
  34. output [range_sign(:from),
  35. sub_text_filter(field, :from, default, opts),
  36. range_sign(:to),
  37. sub_text_filter(field, :to, default, opts)]
  38. end
  39. 1 def range_sign side
  40. dir = side == :from ? "right" : "left"
  41. wrap_with :span, class: "input-group-prepend" do
  42. fa_icon("chevron-circle-#{dir}", class: "input-group-text")
  43. end
  44. end
  45. 1 def sub_text_filter field, subfield, default={}, opts={}
  46. name = "filter[#{field}][#{subfield}]"
  47. value = filter_hash.dig(field, subfield) || default[subfield]
  48. text_filter_with_name_and_value name, value, opts
  49. end
  50. 1 def autocomplete_filter type_code, options_card=nil
  51. options_card ||= Card::Name[type_code, :type, :by_name]
  52. text_filter type_code, "", class: "#{type_code}_autocomplete",
  53. "data-options-card": options_card
  54. end
  55. 1 def multiselect_filter_tag field, default, options, html_options={}
  56. html_options[:multiple] = true
  57. select_filter_tag field, default, options, html_options
  58. end
  59. 1 def select_filter_tag field, default, options, html_options={}
  60. name = filter_name field, html_options[:multiple]
  61. options = options_for_select options, (filter_param(field) || default)
  62. normalize_select_filter_tag_html_options field, html_options
  63. select_tag name, options, html_options
  64. end
  65. # alters html_options hash
  66. 1 def normalize_select_filter_tag_html_options field, html_options
  67. pointer_suffix = html_options[:multiple] ? "multiselect" : "select"
  68. add_class html_options, "pointer-#{pointer_suffix} filter-input #{field} " \
  69. "_filter_input_field _no-select2 form-control"
  70. # _no-select2 because select is initiated after filter is opened.
  71. html_options[:id] = "filter-input-#{unique_id}"
  72. end
  73. 1 def filter_name field, multi=false
  74. "filter[#{field}]#{'[]' if multi}"
  75. end
  76. 1 def filter_options field
  77. raw = send("#{field}_options")
  78. raw.is_a?(Array) ? raw : option_hash_to_array(raw)
  79. end
  80. 1 def option_hash_to_array hash
  81. hash.each_with_object([]) do |(key, value), array|
  82. array << [key, value.to_s]
  83. array
  84. end
  85. end
  86. 1 def type_options type_codename, order="asc", max_length=nil
  87. Card.cache.fetch "#{type_codename}-TYPE-OPTIONS" do
  88. res = Card.search type: type_codename, return: :name, sort: "name", dir: order
  89. max_length ? (res.map { |i| [trim_option(i, max_length), i] }) : res
  90. end
  91. end
  92. 1 def trim_option option, max_length
  93. option.size > max_length ? "#{option[0..max_length]}..." : option
  94. end
  95. end
  96. end;end;end;end;end;
  97. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/abstract/03_filter/form_helper.rb ~~

card/tmpsets/set/mod009-card-mod-search/abstract/03_filter/query_construction.rb

68.18% lines covered

22 relevant lines. 15 lines covered and 7 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Abstract; module Filter;
  3. # Set: Abstract (Filter, QueryConstruction)
  4. #
  5. # all filter keys in the order they were selected
  6. 1 module QueryConstruction;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/abstract/03_filter/query_construction.rb"; end
  9. 1 def all_filter_keys
  10. @all_filter_keys ||= filter_keys_from_params | filter_keys
  11. end
  12. 1 def filter_and_sort_cql
  13. 75 filter_cql.merge(sort_cql)
  14. end
  15. 1 def filter_cql
  16. 75 return {} if filter_hash.empty?
  17. filter_cql_from_params
  18. end
  19. # separate method is needed for tests
  20. 1 def filter_cql_from_params
  21. filter_class.new(filter_keys_with_values, blocked_id_cql).to_cql
  22. end
  23. 1 def sort_cql
  24. 75 sort_hash
  25. end
  26. 1 def blocked_id_cql
  27. not_ids = filter_param :not_ids
  28. not_ids.present? ? { id: ["not in", not_ids.split(",")] } : {}
  29. end
  30. 1 def current_sort
  31. sort_param || default_sort_option
  32. end
  33. 1 def default_sort_option
  34. cql_content[:sort]
  35. end
  36. end;end;end;end;end;
  37. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/abstract/03_filter/query_construction.rb ~~

card/tmpsets/set/mod009-card-mod-search/abstract/04_right_filter_form.rb

68.75% lines covered

16 relevant lines. 11 lines covered and 5 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (RightFilterForm)
  4. #
  5. # To be included in a field card to get a filter for the parent.
  6. 1 module RightFilterForm;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/abstract/04_right_filter_form.rb"; end
  9. # The core view renders a filter for the left card.
  10. 1 include_set Set::Abstract::Filter
  11. 1 def virtual?
  12. new?
  13. end
  14. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  15. 1 def filter_action_path
  16. path mark: card.name.left, view: filter_view
  17. end
  18. 1 view :core, cache: :never do
  19. filter_fields slot_selector: filter_selector
  20. end
  21. 1 def filter_view
  22. :filter_result
  23. end
  24. 1 def filter_selector
  25. ".#{filter_view}-view"
  26. end
  27. end
  28. end;end;end;end;
  29. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/abstract/04_right_filter_form.rb ~~

card/tmpsets/set/mod009-card-mod-search/abstract/05_search.rb

62.75% lines covered

51 relevant lines. 32 lines covered and 19 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (Search)
  4. #
  5. 1 module Search;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/abstract/05_search.rb"; end
  8. 1 include_set Abstract::Paging
  9. 1 include_set Abstract::SearchParams
  10. 1 include_set Abstract::Filter
  11. 1 def search _args={}
  12. raise Error, "search not overridden"
  13. end
  14. 1 def cached_search args={}
  15. 2 @search_results ||= {}
  16. 2 @search_results[args.to_s] ||= search args
  17. end
  18. 1 def returning item, args
  19. 2 args[:return] = item
  20. 2 yield
  21. end
  22. 1 def item_cards args={}
  23. 2 args[:limit] ||= 0
  24. 4 returning(:card, args) { search args }
  25. end
  26. 1 def item_names args={}
  27. args[:limit] ||= 0
  28. returning(:name, args) { search args }
  29. end
  30. 1 def item_ids args={}
  31. args[:limit] ||= 0
  32. returning(:id, args) { search args }
  33. end
  34. 1 def count args={}
  35. args[:offset] = 0
  36. args[:limit] = 0
  37. returning(:count, args) { search args }
  38. end
  39. # for override
  40. 1 def item_type
  41. nil
  42. end
  43. 1 def each_item_name_with_options _content=nil
  44. options = {}
  45. item = fetch_query.statement[:view]
  46. options[:view] = item if item
  47. item_names.each do |name|
  48. yield name, options
  49. end
  50. end
  51. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  52. 1 def search_with_params
  53. 2 search_with_rescue search_params
  54. end
  55. 1 def count_with_params
  56. search_with_rescue search_params.merge(return: :count)
  57. end
  58. 1 def search_with_rescue query_args
  59. 2 card.cached_search query_args
  60. rescue Error::BadQuery => e
  61. Rails.logger.info "BadQuery: #{query_args}"
  62. e
  63. end
  64. 1 def implicit_item_view
  65. view = voo_items_view || item_view_from_query || default_item_view
  66. Card::View.normalize view
  67. end
  68. # override if query can specify item view
  69. 1 def item_view_from_query
  70. nil
  71. end
  72. 1 def with_results
  73. 1 return render_no_search_results if search_with_params.empty?
  74. yield
  75. end
  76. end
  77. end;end;end;end;
  78. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/abstract/05_search.rb ~~

card/tmpsets/set/mod009-card-mod-search/abstract/05_search/views.rb

45.35% lines covered

86 relevant lines. 39 lines covered and 47 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Abstract; module Search;
  3. # Set: Abstract (Search, Views)
  4. #
  5. 1 module Views;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/abstract/05_search/views.rb"; end
  8. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  9. 1 view :search_count, cache: :never do
  10. search_with_params.to_s
  11. end
  12. 1 view :search_error, cache: :never do
  13. sr_class = search_with_params.class.to_s
  14. %(#{sr_class} :: #{search_with_params.message} :: #{card.content})
  15. end
  16. 1 view :card_list, cache: :never do
  17. if search_with_params.empty?
  18. "no results"
  19. else
  20. search_with_params.map do |item_card|
  21. nest_item item_card
  22. end.join "\n"
  23. end
  24. end
  25. end
  26. 2 module JsonFormat; module_parent.send :register_set_format, Card::Format::JsonFormat, self; extend Card::Set::AbstractFormat
  27. 1 AUTOCOMPLETE_LIMIT = 8 # number of name suggestions for autocomplete text fields
  28. 1 def item_cards
  29. search_with_params
  30. end
  31. # NOCACHE because paging_urls is uncacheable hash and thus not safe to merge
  32. 1 view :molecule, cache: :never do
  33. molecule.merge render_paging_urls
  34. end
  35. # TODO: design better autocomplete API
  36. 1 view :name_complete, cache: :never do
  37. complete_search limit: AUTOCOMPLETE_LIMIT
  38. end
  39. 1 view :name_match, cache: :never do
  40. complete_or_match_search limit: AUTOCOMPLETE_LIMIT
  41. end
  42. 1 def complete_or_match_search limit: AUTOCOMPLETE_LIMIT, start_only: false
  43. starts_with = complete_search limit: limit
  44. return starts_with if start_only
  45. remaining_slots = limit - starts_with.size
  46. return starts_with if remaining_slots.zero?
  47. starts_with + match_search(not_names: starts_with, limit: remaining_slots)
  48. end
  49. 1 def complete_search limit: AUTOCOMPLETE_LIMIT
  50. card.search name_cql(limit).merge(complete_cql)
  51. end
  52. 1 def match_search limit: AUTOCOMPLETE_LIMIT, not_names: []
  53. card.search name_cql(limit).merge(match_cql(not_names))
  54. end
  55. 1 def name_cql limit
  56. { limit: limit, sort: "name", return: "name" }
  57. end
  58. 1 def complete_cql
  59. { complete: term_param }
  60. end
  61. 1 def match_cql not_names
  62. cql = { name_match: term_param }
  63. cql[:name] = ["not in"] + not_names if not_names.any?
  64. cql
  65. end
  66. 1 def term_param
  67. params[:term]
  68. end
  69. end
  70. 2 module DataFormat; module_parent.send :register_set_format, Card::Format::DataFormat, self; extend Card::Set::AbstractFormat
  71. 1 view :card_list do
  72. search_with_params.map do |item_card|
  73. nest_item item_card
  74. end
  75. end
  76. end
  77. 2 module CsvFormat; module_parent.send :register_set_format, Card::Format::CsvFormat, self; extend Card::Set::AbstractFormat
  78. 1 view :core, :core, mod: All::AllCsv::CsvFormat
  79. 1 view :card_list do
  80. items = super()
  81. if depth.zero?
  82. title_row + items
  83. else
  84. items
  85. end
  86. end
  87. end
  88. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  89. 1 view :card_list, cache: :never do
  90. 1 with_results do
  91. search_result_list "search-result-list" do |item_card|
  92. card_list_item item_card
  93. end
  94. end
  95. end
  96. 1 view :select_item, cache: :never do
  97. wrap do
  98. haml :select_item
  99. end
  100. end
  101. 1 before :select_item do
  102. class_up "card-slot", "_filter-result-slot"
  103. end
  104. 1 view :checkbox_list, cache: :never do
  105. with_results do
  106. search_result_list "_search-checkbox-list pr-2" do |item_card|
  107. checkbox_item item_card
  108. end
  109. end
  110. end
  111. 1 view :no_search_results do
  112. 1 wrap_with :div, "", class: "search-no-results"
  113. end
  114. 1 private
  115. 1 def card_list_item item_card
  116. nest_item item_card, size: voo.size do |rendered, item_view|
  117. %(<div class="search-result-item item-#{item_view}">#{rendered}</div>)
  118. end
  119. end
  120. 1 def search_result_list klass
  121. with_paging do
  122. wrap_with :div, class: klass do
  123. search_with_params.map do |item_card|
  124. yield item_card
  125. end
  126. end
  127. end
  128. end
  129. 1 def checkbox_item item_card
  130. subformat(item_card).wrap do
  131. haml :checkbox_item, unique_id: unique_id, item_card: item_card
  132. end
  133. end
  134. 1 def closed_limit
  135. [search_params[:limit].to_i, Card.config.closed_search_limit].min
  136. end
  137. end
  138. end;end;end;end;end;
  139. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/abstract/05_search/views.rb ~~

card/tmpsets/set/mod009-card-mod-search/abstract/06_cql_search.rb

88.89% lines covered

63 relevant lines. 56 lines covered and 7 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (CqlSearch)
  4. #
  5. 1 module CqlSearch;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/abstract/06_cql_search.rb"; end
  8. 1 include_set Abstract::Search
  9. 1 def search args={}
  10. 3 with_skipping args do
  11. 3 query = fetch_query(args)
  12. # forces explicit limiting
  13. # can be 0 or less to force no limit
  14. 3 raise "OH NO.. no limit" unless query.mods[:limit]
  15. 3 query.run
  16. end
  17. end
  18. # for override, eg when required subqueries are known to be missing
  19. 1 def skip_search?
  20. 3 false
  21. end
  22. 1 def with_skipping args
  23. 3 skip_search? ? skipped_search_result(args) : yield
  24. end
  25. 1 def skipped_search_result args={}
  26. args[:return] == :count ? 0 : []
  27. end
  28. 1 def cache_query?
  29. 1388 true
  30. end
  31. 1 def fetch_query args={}
  32. 3 @query = nil unless cache_query?
  33. 3 @query ||= {}
  34. 3 @query[args.to_s] ||= query(args.clone) # cache query
  35. end
  36. 1 def query args={}
  37. 3 Query.new standardized_query_args(args), name
  38. end
  39. 1 def standardized_query_args args
  40. 3 args = query_args(args).symbolize_keys
  41. 3 args[:context] ||= name
  42. 3 args
  43. end
  44. 1 def cql_hash
  45. 1310 @cql_hash = nil unless cache_query?
  46. 1310 @cql_hash ||= cql_content.merge filter_and_sort_cql
  47. end
  48. # override this to define search
  49. 1 def cql_content
  50. 75 @cql_content = nil unless cache_query?
  51. 75 @cql_content ||= begin
  52. 75 query = content
  53. 75 query = query.is_a?(Hash) ? query : parse_json_query(query)
  54. 75 query.symbolize_keys
  55. end
  56. end
  57. 1 def query_args args={}
  58. 3 cql_hash.merge args
  59. end
  60. 1 def parse_json_query query
  61. 75 empty_query_error! if query.empty?
  62. 75 JSON.parse query
  63. rescue JSON::ParserError
  64. raise Error::BadQuery, "Invalid JSON search query: #{query}"
  65. end
  66. 1 def empty_query_error!
  67. raise Error::BadQuery, "can't run search with empty content"
  68. end
  69. 1 def item_type
  70. 1305 type = cql_hash[:type]
  71. 1305 return if type.is_a?(Array) || type.is_a?(Hash)
  72. 1301 type
  73. end
  74. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  75. 1 def default_limit
  76. card_content_limit || super
  77. end
  78. 1 def card_content_limit
  79. 1 card.cql_hash&.dig :limit
  80. end
  81. 1 def item_view_from_query
  82. query_with_params.statement[:item]
  83. end
  84. 1 def query_with_params
  85. @query_with_params ||= card.fetch_query search_params
  86. end
  87. 1 def limit
  88. query_with_params.limit
  89. end
  90. end
  91. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  92. 1 def default_limit
  93. 1 card_content_limit || super
  94. end
  95. end
  96. end;end;end;end;
  97. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/abstract/06_cql_search.rb ~~

card/tmpsets/set/mod009-card-mod-search/right/children.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Children" cards
  4. #
  5. 1 module Children;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/right/children.rb"; end
  8. 1 def raw_help_text
  9. "Cards formed by \"mating\" {{_left|name}} with another card. "\
  10. "eg: \"{{_left|name}}+mate\"."
  11. end
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/right/children.rb ~~

card/tmpsets/set/mod009-card-mod-search/right/created.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Created" cards
  4. #
  5. 1 module Created;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/right/created.rb"; end
  8. 1 def raw_help_text
  9. "Cards created by {{_left|name}}."
  10. end
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/right/created.rb ~~

card/tmpsets/set/mod009-card-mod-search/right/edited.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Edited" cards
  4. #
  5. 1 module Edited;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/right/edited.rb"; end
  8. 1 def raw_help_text
  9. "Cards edited by {{_left|name}}."
  10. end
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/right/edited.rb ~~

card/tmpsets/set/mod009-card-mod-search/right/editors.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Editors" cards
  4. #
  5. 1 module Editors;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/right/editors.rb"; end
  8. 1 def raw_help_text
  9. "Users who have edited {{_left|name}}."
  10. end
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/right/editors.rb ~~

card/tmpsets/set/mod009-card-mod-search/right/follow.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Follow" cards
  4. #
  5. 1 module Follow;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/right/follow.rb"; end
  8. 1 def raw_help_text
  9. "Get notified about changes"
  10. end
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/right/follow.rb ~~

card/tmpsets/set/mod009-card-mod-search/right/linked_to_by.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+LinkedToBy" cards
  4. #
  5. 1 module LinkedToBy;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/right/linked_to_by.rb"; end
  8. 1 def raw_help_text
  9. "Cards that link to {{_left|name}}."
  10. end
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/right/linked_to_by.rb ~~

card/tmpsets/set/mod009-card-mod-search/right/links_to.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+LinksTo" cards
  4. #
  5. # -*- encoding : utf-8 -*-
  6. 1 module LinksTo;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/right/links_to.rb"; end
  9. 1 def raw_help_text
  10. "Cards that <em>{{_left|name}}</em> links to."
  11. end
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/right/links_to.rb ~~

card/tmpsets/set/mod009-card-mod-search/right/mates.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Mates" cards
  4. #
  5. 1 module Mates;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/right/mates.rb"; end
  8. 1 def raw_helo_text
  9. "If there is a card named \"X+{{_left|name}}\", then X is a mate of {{_left|name}}."
  10. end
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/right/mates.rb ~~

card/tmpsets/set/mod009-card-mod-search/right/nested_by.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+NestedBy" cards
  4. #
  5. 1 module NestedBy;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/right/nested_by.rb"; end
  8. 1 def raw_help_text
  9. "Cards that include {{_left|name}}."
  10. end
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/right/nested_by.rb ~~

card/tmpsets/set/mod009-card-mod-search/right/nests.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Nests" cards
  4. #
  5. 1 module Nests;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/right/nests.rb"; end
  8. 1 def raw_help_text
  9. "Cards that {{_left|name}} includes."
  10. end
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/right/nests.rb ~~

card/tmpsets/set/mod009-card-mod-search/right/referred_to_by.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+ReferredToBy" cards
  4. #
  5. 1 module ReferredToBy;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/right/referred_to_by.rb"; end
  8. 1 def raw_help_text
  9. "Cards that refer to {{_left|name}}."
  10. end
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/right/referred_to_by.rb ~~

card/tmpsets/set/mod009-card-mod-search/right/refers_to.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+RefersTo" cards
  4. #
  5. 1 module RefersTo;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/right/refers_to.rb"; end
  8. 1 def raw_help_text
  9. "Cards that {{_left|name}} refers to."
  10. end
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/right/refers_to.rb ~~

card/tmpsets/set/mod009-card-mod-search/self/recent.rb

66.67% lines covered

24 relevant lines. 16 lines covered and 8 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Recent"
  4. #
  5. 1 module Recent;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/self/recent.rb"; end
  8. 1 ACTS_PER_PAGE = 25
  9. 1 view :title do
  10. 23 voo.title ||= "Recent Changes"
  11. 23 super()
  12. end
  13. 1 def recent_acts
  14. action_relation = qualifying_actions.where "card_acts.id = card_act_id"
  15. Act.where("EXISTS (#{action_relation.to_sql})").order id: :desc
  16. end
  17. 1 def qualifying_actions
  18. Action.all_viewable.where "draft is not true"
  19. end
  20. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  21. 1 view :core do
  22. voo.hide :history_legend unless voo.main
  23. @acts_per_page = ACTS_PER_PAGE
  24. acts_layout card.recent_acts, :absolute
  25. end
  26. end
  27. 2 module RssFormat; module_parent.send :register_set_format, Card::Format::RssFormat, self; extend Card::Set::AbstractFormat
  28. 1 view :feed_item_description do
  29. render_blank
  30. end
  31. end
  32. 2 module JsonFormat; module_parent.send :register_set_format, Card::Format::JsonFormat, self; extend Card::Set::AbstractFormat
  33. 1 def items_for_export
  34. card.item_cards limit: 20
  35. end
  36. end
  37. end;end;end;end;
  38. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/self/recent.rb ~~

card/tmpsets/set/mod009-card-mod-search/self/search.rb

42.31% lines covered

52 relevant lines. 22 lines covered and 30 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Search"
  4. #
  5. 1 module Search;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/self/search.rb"; end
  8. 1 def query_args args={}
  9. return super unless keyword_contains_cql? args
  10. args.merge parse_keyword_cql(args)
  11. end
  12. 1 def parse_keyword_cql args
  13. parse_json_query(args[:vars][:keyword])
  14. end
  15. 1 def keyword_contains_cql? hash
  16. hash[:vars] && (keyword = hash[:vars][:keyword]) && keyword =~ /^\{.+\}$/
  17. end
  18. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  19. 1 view :search_error, cache: :never do
  20. sr_class = search_with_params.class.to_s
  21. # don't show card content; not very helpful in this case
  22. %(#{sr_class} :: #{search_with_params.message})
  23. end
  24. end
  25. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  26. 1 view :title, cache: :never do
  27. return super() unless (keyword = search_keyword) &&
  28. (title = keyword_search_title(keyword))
  29. voo.title = title
  30. end
  31. 1 def keyword_search_title keyword
  32. %(Search results for: <span class="search-keyword">#{h keyword}</span>)
  33. end
  34. 1 def search_keyword
  35. (vars = search_vars) && vars[:keyword]
  36. rescue Card::Error::PermissionDenied
  37. nil
  38. end
  39. 1 def search_vars
  40. root.respond_to?(:search_params) ? root.search_params[:vars] : search_params[:vars]
  41. end
  42. 1 def cql_search?
  43. card.keyword_contains_cql? vars: search_vars
  44. end
  45. end
  46. 2 module JsonFormat; module_parent.send :register_set_format, Card::Format::JsonFormat, self; extend Card::Set::AbstractFormat
  47. 1 view :complete, cache: :never do
  48. term = term_param
  49. exact = Card.fetch term, new: {}
  50. {
  51. search: true,
  52. term: term,
  53. add: add_item(exact),
  54. new: new_item_of_type(exact),
  55. goto: goto_items(term, exact)
  56. }
  57. end
  58. 1 def add_item exact
  59. return unless exact.new_card? &&
  60. exact.name.valid? &&
  61. !exact.virtual? &&
  62. exact.ok?(:create)
  63. [h(exact.name), exact.name.url_key]
  64. end
  65. 1 def new_item_of_type exact
  66. return unless (exact.type_id == CardtypeID) &&
  67. Card.new(type_id: exact.id).ok?(:create)
  68. [exact.name, "new/#{exact.name.url_key}"]
  69. end
  70. 1 def goto_items term, exact
  71. goto_names = complete_or_match_search start_only: Card.config.navbox_match_start_only
  72. goto_names.unshift exact.name if add_exact_to_goto_names? exact, goto_names
  73. goto_names.map do |name|
  74. [name, name.to_name.url_key, h(highlight(name, term, sanitize: false))]
  75. end
  76. end
  77. 1 def add_exact_to_goto_names? exact, goto_names
  78. exact.known? && !goto_names.find { |n| n.to_name.key == exact.key }
  79. end
  80. 1 def term_param
  81. term = query_params[:keyword]
  82. if (term =~ /^\+/) && (main = params["main"])
  83. term = main + term
  84. end
  85. term
  86. end
  87. end
  88. end;end;end;end;
  89. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/self/search.rb ~~

card/tmpsets/set/mod009-card-mod-search/type/search_type.rb

54.35% lines covered

46 relevant lines. 25 lines covered and 21 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "SearchType" cards
  4. #
  5. 1 module SearchType;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-search/set/type/search_type.rb"; end
  8. 1 include_set Type::Json
  9. 1 include_set Abstract::CqlSearch
  10. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  11. 1 view :core, cache: :never do
  12. _render search_result_view
  13. end
  14. 1 def chunk_list
  15. 20 :query
  16. end
  17. 1 def search_result_view
  18. 1 case search_with_params
  19. when Exception then :search_error
  20. when Integer then :search_count
  21. when nest_mode == :template then :raw
  22. 1 else :card_list
  23. end
  24. end
  25. end
  26. 2 module JsonFormat; module_parent.send :register_set_format, Card::Format::JsonFormat, self; extend Card::Set::AbstractFormat
  27. 1 def items_for_export
  28. return [] if card.content.empty? || unexportable_tag?(card.name.tag_name.key)
  29. card.item_cards
  30. end
  31. # avoid running the search from +:content_options (huge results)
  32. # and +:structure (errors)
  33. # TODO: make this configurable in set mods
  34. 1 def unexportable_tag? tag_key
  35. %i[content_options structure].map { |code| code.cardname.key }.include? tag_key
  36. end
  37. end
  38. 2 module RssFormat; module_parent.send :register_set_format, Card::Format::RssFormat, self; extend Card::Set::AbstractFormat
  39. 1 view :feed_body do
  40. case raw_feed_items
  41. when Exception then @xml.item(render!(:search_error))
  42. when Integer then @xml.item(render!(:search_count))
  43. else super()
  44. end
  45. end
  46. 1 def raw_feed_items
  47. @raw_feed_items ||= search_with_params
  48. end
  49. end
  50. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  51. 1 view :core do
  52. 1 _render search_result_view
  53. end
  54. 1 view :bar do
  55. voo.hide :one_line_content
  56. super()
  57. end
  58. 1 view :one_line_content, cache: :never do
  59. if depth > max_depth
  60. "..."
  61. else
  62. search_params[:limit] = closed_limit
  63. _render_core hide: "paging", items: { view: :link }
  64. # TODO: if item is queryified to be "name", then that should work.
  65. # otherwise use link
  66. end
  67. end
  68. 1 def rss_link_tag
  69. path_opts = { format: :rss }
  70. Array(search_params[:vars]).compact.each { |k, v| opts["_#{k}"] = v }
  71. tag "link", rel: "alternate",
  72. type: "application/rss+xml",
  73. title: "RSS",
  74. href: path(path_opts)
  75. end
  76. end
  77. end;end;end;end;
  78. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-search/set/type/search_type.rb ~~

card/tmpsets/set/mod010-standard/all/comment.rb

44.44% lines covered

45 relevant lines. 20 lines covered and 25 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Comment)
  4. #
  5. 1 module Comment;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/comment.rb"; end
  8. 1 def commenting?
  9. 323 comment && action != :delete
  10. end
  11. 1 event :add_comment, :prepare_to_store, on: :save, when: :comment do
  12. Env.session[:comment_author] = comment_author if Env.session
  13. return unless comment.present?
  14. self.content =
  15. [content, format.comment_with_signature].compact.join "\n<hr\>\n"
  16. self.comment = nil
  17. end
  18. 1 attr_writer :comment_author
  19. 1 def comment_author
  20. @comment_author ||=
  21. Env.session[:comment_author] || Env.params[:comment_author] || "Anonymous"
  22. end
  23. 1 def clean_comment
  24. comment.split(/\n/).map do |line|
  25. "<p>#{line.strip.empty? ? '&nbsp;' : line}</p>"
  26. end * "\n"
  27. end
  28. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  29. 1 def comment_with_signature
  30. card.clean_comment + "\n" + comment_signature
  31. end
  32. 1 def comment_signature
  33. wrap_with :div, class: "w-comment-author" do
  34. "#{comment_author}.....#{Time.zone.now}"
  35. end
  36. end
  37. 1 def comment_author
  38. if Auth.signed_in?
  39. "[[#{Auth.current.name}]]"
  40. else
  41. "#{card.comment_author} (Not signed in)"
  42. end
  43. end
  44. 1 view :comment_box, denial: :blank, unknown: true, perms: :update do
  45. wrap_with :div, class: "comment-box nodblclick" do
  46. action = card.new_card? ? :create : :update
  47. card_form action do
  48. [hidden_comment_fields, comment_box, comment_buttons]
  49. end
  50. end
  51. end
  52. 1 def hidden_comment_fields
  53. return unless card.new_card?
  54. hidden_field_tag "card[name]", card.name
  55. # FIXME: wish we had more generalized solution for names.
  56. # without this, nonexistent cards will often take left's linkname.
  57. # (needs test)
  58. end
  59. 1 def comment_box
  60. text_area :comment, rows: 3
  61. end
  62. 1 def comment_buttons
  63. wrap_with :div, class: "comment-buttons" do
  64. [comment_author_label, comment_submit_button]
  65. end
  66. end
  67. 1 def comment_author_label
  68. return if Auth.signed_in?
  69. %(<label>My Name is:</label> #{text_field :comment_author})
  70. end
  71. 1 def comment_submit_button
  72. submit_button text: "Comment", type: :submit, disable_with: "Commenting"
  73. end
  74. end
  75. end;end;end;end;
  76. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/comment.rb ~~

card/tmpsets/set/mod010-standard/all/error.rb

59.09% lines covered

44 relevant lines. 26 lines covered and 18 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Error)
  4. #
  5. 1 module Error;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/error.rb"; end
  8. 1 def copy_errors card
  9. card.errors.each do |att, msg|
  10. errors.add att, msg
  11. end
  12. end
  13. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  14. 1 view :compact_missing, perms: :none, compact: true do
  15. ""
  16. end
  17. 1 view :unknown, perms: :none, cache: :never do
  18. ""
  19. end
  20. 1 view :server_error, perms: :none do
  21. tr(:server_error)
  22. end
  23. 1 view :denial, perms: :none do
  24. focal? ? tr(:denial) : ""
  25. end
  26. 1 view :not_found, perms: :none do
  27. error_name = card.name.present? ? safe_name : tr(:not_found_no_name)
  28. tr(:not_found_named, cardname: error_name)
  29. end
  30. 1 view :bad_address, perms: :none do
  31. 1 root.error_status = 404
  32. 1 tr(:bad_address)
  33. end
  34. 1 view :errors do
  35. ["Problem:", "", standard_errors].flatten.join "\n"
  36. end
  37. 1 def standard_errors
  38. card.errors.map do |attrib, msg|
  39. attrib == :abort ? msg : standard_error_message(attrib, msg)
  40. end
  41. end
  42. # for override
  43. 1 def standard_error_message attribute, message
  44. "#{attribute.to_s.upcase}: #{message}"
  45. end
  46. 1 def unsupported_view_error_message view
  47. tr(:unsupported_view, view: view, cardname: card.name)
  48. end
  49. end
  50. 2 module JsonFormat; module_parent.send :register_set_format, Card::Format::JsonFormat, self; extend Card::Set::AbstractFormat
  51. 1 view :errors do
  52. format_error error_list
  53. end
  54. 1 view :server_error, :errors
  55. 1 view :denial, :errors
  56. 1 view :not_found, :errors
  57. 1 view :bad_address do
  58. format_error super()
  59. end
  60. 1 def format_error error
  61. { error_status: error_status, errors: error }
  62. end
  63. 1 def error_list
  64. card.errors.each_with_object([]) do |(field, message), list|
  65. list << { field: field, message: message }
  66. end
  67. end
  68. end
  69. end;end;end;end;
  70. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/error.rb ~~

card/tmpsets/set/mod010-standard/all/links.rb

91.55% lines covered

71 relevant lines. 65 lines covered and 6 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Links)
  4. #
  5. 1 module Links;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/links.rb"; end
  8. 1 RESOURCE_TYPE_REGEXP = /^([a-zA-Z][\-+\.a-zA-Z\d]*):/
  9. # The #link_to methods support smart formatting of links in multiple formats.
  10. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  11. # Creates a "link", the meaning of which depends upon the format. In this base
  12. # format, the link looks like [text][absolute path]
  13. #
  14. # @param text [String] optional string associated with link
  15. # @param opts [Hash] optional Hash. In simple formats, :path is usually the only key
  16. 1 def link_to text=nil, opts={}
  17. 26 path = path((opts.delete(:path) || {}))
  18. 26 if text && path != text
  19. "#{text}[#{path}]"
  20. else
  21. 26 path
  22. end
  23. end
  24. # link to a different view of the current card
  25. # @param view [Symbol,String]
  26. # @param text [String]
  27. # @param opts [Hash]
  28. 1 def link_to_view view, text=nil, opts={}
  29. 49 add_to_path opts, view: view unless view == :home
  30. 49 link_to text, opts
  31. end
  32. # link to a card other than the current card.
  33. # @param cardish [Integer, Symbol, String, Card] a card identifier
  34. # @param text [String]
  35. # @param opts [Hash]
  36. 1 def link_to_card cardish, text=nil, opts={}
  37. 197 add_to_path opts, mark: Card::Name[cardish]
  38. 197 link_to text, opts
  39. end
  40. # a "resource" is essentially a reference to something that
  41. # decko doesn't recognize to be a card. Can be a remote url,
  42. # a local url (that decko hasn't parsed) or a local path.
  43. # @param resource [String]
  44. # @param text [String]
  45. # @param opts [Hash]
  46. 1 def link_to_resource resource, text=nil, opts={}
  47. 95 resource = clean_resource resource, resource_type(resource)
  48. 95 link_to text, opts.merge(path: resource)
  49. end
  50. # smart_link_to is wrapper method for #link_to, #link_to_card, #link_to_view, and
  51. # #link_to_resource. If the opts argument contains :view, :related, :card, or
  52. # :resource, it will use the respective method to render a link.
  53. #
  54. # This is usually most useful when writing views that generate many different
  55. # kinds of links.
  56. 1 def smart_link_to text, opts={}
  57. if (linktype = %i[view card resource].find { |key| opts[key] })
  58. send "link_to_#{linktype}", opts.delete(linktype), text, opts
  59. else
  60. send :link_to, text, opts
  61. end
  62. end
  63. 1 private
  64. 1 def resource_type resource
  65. 164 case resource
  66. 48 when /^https?\:/ then "external-link"
  67. 116 when %r{^/} then "internal-link"
  68. when /^mailto\:/ then "email-link"
  69. when RESOURCE_TYPE_REGEXP then Regexp.last_match(1) + "-link"
  70. end
  71. end
  72. 1 def clean_resource resource, resource_type
  73. 95 if resource_type == "internal-link"
  74. 70 contextualize_path resource[1..-1]
  75. else
  76. 25 resource
  77. end
  78. end
  79. 1 def add_to_path opts, new_hash
  80. 246 opts[:path] = (opts[:path] || {}).merge new_hash
  81. end
  82. end
  83. 1 public
  84. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  85. # in HTML, #link_to renders an anchor tag <a>
  86. # it treats opts other than "path" as html opts for that tag,
  87. # and it adds special handling of "remote" and "method" opts
  88. # (changes them into data attributes)
  89. 1 def link_to text=nil, opts={}
  90. 360 opts[:href] ||= path opts.delete(:path)
  91. 360 text = raw(text || opts[:href])
  92. 360 interpret_data_opts_to_link_to opts
  93. 360 wrap_with :a, text, opts
  94. end
  95. # in HTML, #link_to_card adds special css classes indicated whether a
  96. # card is "known" (real or virtual) or "wanted" (unknown)
  97. # TODO: upgrade from (known/wanted)-card to (real/virtual/unknown)-card
  98. 1 def link_to_card cardish, text=nil, opts={}
  99. 197 name = Card::Name[cardish]
  100. 197 slotterify opts if opts[:slotter]
  101. 197 add_known_or_wanted_class opts, name
  102. 197 super name, (text || name), opts
  103. end
  104. # in HTML, #link_to_view defaults to a remote link with rel="nofollow".
  105. 1 def link_to_view view, text=nil, opts={}
  106. 49 slotterify opts
  107. 49 super view, (text || view), opts
  108. end
  109. # in HTML, #link_to_resource automatically adds a target to external resources
  110. # so they will open in another tab. It also adds css classes indicating whether
  111. # the resource is internal or external
  112. 1 def link_to_resource resource, text=nil, opts={}
  113. 69 add_resource_opts opts, resource_type(resource)
  114. 69 super
  115. end
  116. 1 private
  117. 1 def slotterify opts
  118. 61 opts.delete(:slotter)
  119. 61 opts.reverse_merge! remote: true, rel: "nofollow"
  120. 61 add_class opts, "slotter"
  121. end
  122. 1 def add_known_or_wanted_class opts, name
  123. 197 known = opts.delete :known
  124. 197 known = Card.known?(name) if known.nil?
  125. 197 add_class opts, (known ? "known-card" : "wanted-card")
  126. end
  127. 1 def interpret_data_opts_to_link_to opts
  128. 360 %i[remote method].each do |key|
  129. 720 next unless (val = opts.delete key)
  130. 62 opts["data-#{key}"] = val
  131. end
  132. end
  133. 1 def add_resource_opts opts, resource_type
  134. 69 opts[:target] ||= "_blank" if resource_type == "external-link"
  135. 69 add_class opts, resource_type
  136. end
  137. end
  138. end;end;end;end;
  139. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/links.rb ~~

card/tmpsets/set/mod010-standard/all/list_changes.rb

80.77% lines covered

26 relevant lines. 21 lines covered and 5 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (ListChanges)
  4. #
  5. # -*- encoding : utf-8 -*-
  6. 1 module ListChanges;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/list_changes.rb"; end
  9. 1 def list_fields
  10. 19 Card.search({ left: name, type_id: Card::MirroredListID }, "list fields")
  11. end
  12. 1 def listed_by_fields
  13. 19 Card.search({ left: name, type_id: Card::MirrorListID }, "listed by fields")
  14. end
  15. 1 def linker_lists
  16. 197 Card.search({ type_id: Card::MirroredListID, link_to: name },
  17. "lists that link to #{name}")
  18. end
  19. 1 def codename_list_exist?
  20. 216 Card::Codename.exists?(:mirrored_list) && Card::Codename.exists?(:mirror_list)
  21. end
  22. 1 event :trunk_cardtype_of_a_list_relation_changed, :finalize,
  23. changed: :type, on: :update, when: :codename_list_exist? do
  24. 1 type_key_was = Card.quick_fetch(type_id_before_act)&.key
  25. 1 list_fields.each do |card|
  26. card.update_listed_by_cache_for card.item_keys, type_key: type_key_was
  27. card.update_listed_by_cache_for card.item_keys
  28. end
  29. 1 listed_by_fields.each &:update_cached_list
  30. end
  31. 1 event :trunk_name_of_a_list_relation_changed, :finalize,
  32. changed: :name, on: :update,
  33. when: :codename_list_exist? do
  34. 18 list_fields.each do |card|
  35. card.update_listed_by_cache_for card.item_keys
  36. end
  37. 18 listed_by_fields.each &:update_cached_list
  38. end
  39. 1 event :cardtype_of_list_item_changed, :validate,
  40. changed: :type, on: :save,
  41. when: :codename_list_exist? do
  42. 197 linker_lists.each do |card|
  43. next unless card.item_type_id != type_id
  44. errors.add(:type,
  45. "can't be changed because #{name} " \
  46. "is referenced by list card #{card.name}")
  47. end
  48. end
  49. end;end;end;end;
  50. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/list_changes.rb ~~

card/tmpsets/set/mod010-standard/all/path.rb

89.61% lines covered

77 relevant lines. 69 lines covered and 8 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Path)
  4. #
  5. 1 module Path;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/path.rb"; end
  8. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  9. # Decko uses "path" a bit unusually. In most formats, it returns a full url. In HTML,
  10. # it provides everything after the domain/port.
  11. #
  12. # If you're feeling your saucy oats, you might point out that typically "paths" don't
  13. # include queries and fragment identifiers, much less protocols, domains, and ports.
  14. # 10 pedantry points to you! But "path" has just four letters and is smart about
  15. # format needs, so using it will lead you down the right ... something or other.
  16. # Format#path is for generating standard card routes, eg, assuming the card
  17. # associated with the current format is named "current", it will generate paths like
  18. # these:
  19. # path view: :bar -> "current?view=bar"
  20. # path mark: [mycardid] -> "mycardname"
  21. # path format: :csv) -> "current.csv"
  22. # path action: :update -> "update/current"
  23. # #path produces paths that follow one of three main patterns:
  24. # 1. mark[.format][?query] # standard GET request
  25. # 2. action/mark[?query] # GET variant of standard actions
  26. # 3. new/mark # shortcut for "new" view of cardtype
  27. # @param opts [Hash, String] a String is treated as a complete path and
  28. # bypasses all processing
  29. # @option opts [String, Card::Name, Integer, Symbol, Card] :mark
  30. # @option opts [Symbol] :action card action (:create, :update, :delete)
  31. # @option opts [Symbol] :format
  32. # @option opts [Hash] :card
  33. # @option opts [TrueClass] :no_mark
  34. 1 CAST_PARAMS = { slot: { hide: :array, show: :array, wrap: :array } }.freeze
  35. # TODO: monkey API for this
  36. 1 def path opts={}
  37. 463 return opts unless opts.is_a? Hash
  38. 355 path = new_cardtype_path(opts) || standard_path(opts)
  39. 355 contextualize_path path
  40. end
  41. # in base format (and therefore most other formats), even internal paths
  42. # are rendered as absolute urls.
  43. 1 def contextualize_path relative_path
  44. 3 card_url relative_path
  45. end
  46. 1 private
  47. 1 def new_cardtype_path opts
  48. 355 return unless valid_opts_for_new_cardtype_path? opts
  49. 15 "#{opts.delete :action}/#{path_mark opts}#{path_query opts}"
  50. end
  51. 1 def valid_opts_for_new_cardtype_path? opts
  52. 355 return unless opts[:action].in? %i[new type]
  53. # "new" and "type" are not really an action and are only
  54. # a valid value here for this path
  55. 15 opts[:mark].present?
  56. end
  57. 1 def standard_path opts
  58. 340 path_base(opts) + path_extension(opts) + path_query(opts)
  59. end
  60. 1 def path_base opts
  61. 340 mark = path_mark opts
  62. 340 if (action = path_action opts)
  63. 39 action_base action, mark
  64. else
  65. 301 mark
  66. end
  67. end
  68. 1 def action_base action, mark
  69. 39 mark.present? ? "#{action}/#{mark}" : "card/#{action}"
  70. # the card/ prefix prevents interpreting action as cardname
  71. end
  72. 1 def path_action opts
  73. 340 return unless (action = opts.delete(:action)&.to_sym)
  74. 124 %i[create update delete].find { |a| a == action }
  75. end
  76. 1 def path_mark opts
  77. 355 return "" if markless_path? opts
  78. 347 name = opts[:mark] ? Card::Name[opts.delete(:mark)] : card.name
  79. 347 add_unknown_name_to_opts name.to_name, opts
  80. 347 name.to_name.url_key
  81. end
  82. 1 def markless_path? opts
  83. 355 opts[:action] == :create || opts.delete(:no_mark)
  84. end
  85. 1 def path_extension opts
  86. 340 extension = opts.delete :format
  87. 340 extension ? ".#{extension}" : ""
  88. end
  89. 1 def path_query opts
  90. 355 opts = cast_path_opts opts
  91. 355 opts.empty? ? "" : "?#{opts.to_param}"
  92. end
  93. # normalizes certain path opts to specified data types
  94. 1 def cast_path_opts opts, cast_hash=nil
  95. 355 cast_hash ||= CAST_PARAMS
  96. 355 return opts unless opts.is_a?(::Hash)
  97. 355 opts.each do |key, value|
  98. 105 next unless (cast_to = cast_hash[key])
  99. opts[key] = cast_path_value value, cast_to
  100. end
  101. end
  102. 1 def cast_path_value value, cast_to
  103. if cast_to.is_a? Hash
  104. cast_path_opts value, cast_to
  105. else
  106. send "cast_path_value_as_#{cast_to}", value
  107. end
  108. end
  109. 1 def cast_path_value_as_array value
  110. Array.wrap value
  111. end
  112. 1 def add_unknown_name_to_opts name, opts
  113. 347 return if name_specified?(opts) || name_standardish?(name) || Card.known?(name)
  114. opts[:card] ||= {}
  115. opts[:card][:name] = name
  116. end
  117. 1 def name_specified? opts
  118. 347 opts[:card] && opts[:card][:name]
  119. end
  120. # no name info will be lost by using url_key
  121. 1 def name_standardish? name
  122. 347 name.s == Card::Name.url_key_to_standard(name.url_key)
  123. end
  124. end
  125. 2 module JsonFormat; module_parent.send :register_set_format, Card::Format::JsonFormat, self; extend Card::Set::AbstractFormat
  126. 1 def add_unknown_name_to_opts name, opts
  127. # noop
  128. end
  129. end
  130. 2 module CssFormat; module_parent.send :register_set_format, Card::Format::CssFormat, self; extend Card::Set::AbstractFormat
  131. 1 def contextualize_path relative_path
  132. 24 if Card.config.file_storage == :local
  133. # absolute paths lead to invalid assets path in css for cukes
  134. 24 card_path relative_path
  135. else
  136. # ...but relative paths are problematic when machine output and
  137. # hard-coded assets (like fonts) are on different servers
  138. card_url relative_path
  139. end
  140. end
  141. end
  142. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  143. # in HTML, decko paths rendered as relative to the site's root.
  144. 1 def contextualize_path relative_path
  145. 418 card_path relative_path
  146. end
  147. end
  148. 2 module EmailHtmlFormat; module_parent.send :register_set_format, Card::Format::EmailHtmlFormat, self; extend Card::Set::AbstractFormat
  149. 1 def contextualize_path relative_path
  150. 6 card_url relative_path
  151. end
  152. end
  153. end;end;end;end;
  154. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/path.rb ~~

card/tmpsets/set/mod010-standard/all/rich_html.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (RichHtml)
  4. #
  5. 1 module RichHtml;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 delegate :class_up, :class_down, :with_class_up, :without_upped_class, :classy,
  10. to: :voo
  11. end
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html.rb ~~

card/tmpsets/set/mod010-standard/all/rich_html/alert.rb

100.0% lines covered

17 relevant lines. 17 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module RichHtml;
  3. # Set: All cards (RichHtml, Alert)
  4. #
  5. 1 module Alert;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/alert.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. # alert_types: 'success', 'info', 'warning', 'danger'
  10. 1 def alert alert_type, dismissable=false, disappear=false, args={}
  11. 11 add_class args, alert_classes(alert_type, dismissable, disappear)
  12. 11 wrap_with :div, args.merge(role: "alert") do
  13. 11 [(alert_close_button if dismissable), output(yield)]
  14. end
  15. end
  16. 1 def alert_classes alert_type, dismissable, disappear
  17. 11 classes = ["alert", "alert-#{alert_type}"]
  18. 11 classes << "alert-dismissible " if dismissable
  19. 11 classes << "_disappear" if disappear
  20. 11 classy classes
  21. end
  22. 1 def alert_close_button
  23. 11 wrap_with :button, type: "button", "data-dismiss": "alert",
  24. class: "close", "aria-label": "Close" do
  25. 11 wrap_with :span, "&times;", "aria-hidden" => true
  26. end
  27. end
  28. end
  29. end;end;end;end;end;
  30. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/alert.rb ~~

card/tmpsets/set/mod010-standard/all/rich_html/content.rb

62.89% lines covered

97 relevant lines. 61 lines covered and 36 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module RichHtml;
  3. # Set: All cards (RichHtml, Content)
  4. #
  5. 1 module Content;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/content.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def prepare_content_slot
  10. 25 class_up "card-slot", "d0-card-content"
  11. 25 voo.hide :menu
  12. end
  13. 26 before(:content) { prepare_content_slot }
  14. 1 view :content do
  15. 24 voo.hide :edit_button
  16. 24 wrap do
  17. 24 [_render_menu, _render_core, _render_edit_button(edit: :inline)]
  18. end
  19. end
  20. 1 before(:content_with_edit_button) do
  21. prepare_content_slot
  22. end
  23. 1 view :content_with_edit_button do
  24. wrap do
  25. [_render_menu, _render_core, _render_edit_button(edit: :inline)]
  26. end
  27. end
  28. 1 view :short_content, wrap: { div: { class: "text-muted" } } do
  29. 25 short_content
  30. end
  31. 1 view :raw_one_line_content, unknown: :mini_unknown,
  32. wrap: { div: { class: "text-muted" } } do
  33. raw_one_line_content
  34. end
  35. 1 view :one_line_content, unknown: :mini_unknown,
  36. wrap: { div: { class: "text-muted" } } do
  37. one_line_content
  38. end
  39. 1 before(:content_with_title) { prepare_content_slot }
  40. 1 view :content_with_title do
  41. wrap true, title: card.format(:text).render_core do
  42. [_render_menu, _render_core]
  43. end
  44. end
  45. 1 before :content_panel do
  46. prepare_content_slot
  47. class_up "card-slot", "card"
  48. end
  49. 1 view :content_panel do
  50. wrap do
  51. wrap_with :div, class: "card-body" do
  52. [_render_menu, _render_core]
  53. end
  54. end
  55. end
  56. 1 view :titled do
  57. @content_body = true
  58. wrap do
  59. [
  60. naming { render_header },
  61. render_flash,
  62. wrap_body { render_titled_content },
  63. render_comment_box(optional: :hide)
  64. ]
  65. end
  66. end
  67. 1 view :labeled, unknown: true do
  68. @content_body = true
  69. wrap(true, class: "row") do
  70. labeled(render_title, wrap_body { "#{render_menu}#{render_labeled_content}" } )
  71. end
  72. end
  73. 1 def labeled label, content
  74. haml :labeled, label: label, content: content
  75. end
  76. 1 def labeled_field field, item_view=:name, opts={}
  77. opts[:title] ||= Card.fetch_name field
  78. field_nest field, opts.merge(view: :labeled,
  79. items: (opts[:items] || {}).merge(view: item_view))
  80. end
  81. 1 view :open do
  82. 4 toggle_logic
  83. 4 @toggle_mode = :open
  84. 4 @content_body = true
  85. 4 frame do
  86. 4 [_render_open_content, render_comment_box(optional: :hide)]
  87. end
  88. end
  89. 1 view :closed do
  90. 1 with_nest_mode :compact do
  91. 1 toggle_logic
  92. 1 class_up "d0-card-body", "closed-content"
  93. 1 @content_body = false
  94. 1 @toggle_mode = :close
  95. 1 frame
  96. end
  97. end
  98. 1 def toggle_logic
  99. 5 show_view?(:title_link, :hide) ? voo.show(:icon_toggle) : voo.show(:title_toggle)
  100. end
  101. 1 def current_set_card
  102. set_name = params[:current_set]
  103. set_name ||= "#{card.name}+*type" if card.known? && card.type_id == Card::CardtypeID
  104. set_name ||= "#{card.name}+*self"
  105. Card.fetch(set_name)
  106. end
  107. 1 def raw_one_line_content
  108. cleaned = Card::Content.clean! render_raw, {}
  109. cut_with_ellipsis cleaned
  110. end
  111. 1 def one_line_content
  112. # TODO: use a version of Card::Content.smart_truncate
  113. # that counts characters instead of clean!
  114. cleaned = Card::Content.clean! render_core, {}
  115. cut_with_ellipsis cleaned
  116. end
  117. # LOCALIZE
  118. 1 def short_content
  119. 23 short_content_items || short_content_fields || short_content_from_core
  120. end
  121. 1 def short_content_items
  122. 23 return unless card.respond_to? :count
  123. "#{count} #{'item'.pluralize count}"
  124. end
  125. 1 def short_content_fields
  126. 23 with_short_content_fields do |num_fields|
  127. "#{num_fields} #{'field'.pluralize num_fields}" if num_fields.positive?
  128. end
  129. end
  130. 1 def with_short_content_fields
  131. 23 yield nested_field_names.size if voo.structure || card.structure
  132. end
  133. 1 def short_content_from_core
  134. 23 content = render_core
  135. 3 if content.blank?
  136. 1 "empty"
  137. 2 elsif content.size <= 5
  138. content
  139. 2 elsif content.count("\n") < 2
  140. 2 "#{content.size} characters"
  141. else
  142. "#{content.count("\n") + 1} lines"
  143. end
  144. end
  145. 1 def count
  146. @count ||= card.count
  147. end
  148. end
  149. end;end;end;end;end;
  150. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/content.rb ~~

card/tmpsets/set/mod010-standard/all/rich_html/error.rb

84.69% lines covered

98 relevant lines. 83 lines covered and 15 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module RichHtml;
  3. # Set: All cards (RichHtml, Error)
  4. #
  5. 1 module Error;
  6. 1 extend Card::Set
  7. 2 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/error.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :server_error, template: :haml
  10. 1 view :debug_server_error, wrap: { modal: { size: :full } } do
  11. error_page = BetterErrors::ErrorPage.new Card::Error.current,
  12. "PATH_INFO" => request.env["REQUEST_URI"]
  13. haml :debug_server_error, {}, error_page
  14. end
  15. 1 view :unknown do
  16. 6 createable { wrap { unknown_link "#{unknown_icon} #{render_title}" } }
  17. end
  18. # icon only, no wrap
  19. 1 view :mini_unknown, unknown: true, cache: :never do
  20. createable { unknown_link unknown_icon }
  21. end
  22. 1 def createable
  23. 2 card.ok?(:create) ? yield : ""
  24. end
  25. 1 def unknown_link text
  26. 2 path_opts = voo.type ? { card: { type: voo.type } } : {}
  27. 2 link_to_view :new_in_modal, text, path: path_opts, class: classy("unknown-link")
  28. end
  29. 1 def unknown_icon
  30. 2 fa_icon "plus-square"
  31. end
  32. 1 view :compact_missing, perms: :none do
  33. wrap_with :span, h(title_in_context), class: "text-muted"
  34. end
  35. 1 view :conflict, cache: :never do
  36. actor_link = link_to_card card.last_action.act.actor.name
  37. class_up "card-slot", "error-view"
  38. wrap do # LOCALIZE
  39. alert "warning" do
  40. %(
  41. <strong>Conflict!</strong>
  42. <span class="new-current-revision-id">#{card.last_action_id}</span>
  43. <div>#{actor_link} has also been making changes.</div>
  44. <div>Please examine below, resolve above, and re-submit.</div>
  45. #{render_act}
  46. )
  47. end
  48. end
  49. end
  50. 1 view :errors, perms: :none do
  51. 2 return if card.errors.empty?
  52. 2 voo.title = card.name.blank? ? "Problems" : tr(:problems_name, cardname: card.name)
  53. 2 voo.hide! :menu
  54. 2 class_up "alert", "card-error-msg"
  55. 2 standard_errors voo.title
  56. end
  57. 1 view :not_found do
  58. 2 voo.hide! :menu
  59. 2 voo.title = "Not Found"
  60. 2 frame do
  61. 2 [not_found_errors, sign_in_or_up_links("to create it")]
  62. end
  63. end
  64. 1 view :denial do
  65. 5 focal? ? loud_denial : quiet_denial
  66. end
  67. 1 def view_for_unknown view
  68. 4 main? && ok?(:create) ? :new : super
  69. end
  70. 1 def show_all_errors?
  71. # make configurable by env
  72. 2 Auth.always_ok? || Rails.env.development?
  73. end
  74. 1 def error_cardname exception
  75. 2 cardname = super
  76. 2 show_all_errors? ? backtrace_link(cardname, exception) : cardname
  77. end
  78. 1 def rendering_error exception, view
  79. 6 wrap_with(:span, class: "render-error alert alert-danger") { super }
  80. end
  81. 1 def error_modal_id
  82. @error_modal_id ||= unique_id
  83. end
  84. 1 def error_message exception
  85. %{
  86. <h3>Error message (visible to admin only)</h3>
  87. <p><strong>#{CGI.escapeHTML exception.message}</strong></p>
  88. <div>#{exception.backtrace * "<br>\n"}</div>
  89. }
  90. end
  91. 1 def backtrace_link cardname, exception
  92. # TODO: make this a modal link after new modal handling is merged in
  93. wrap_with(:span, title: error_message(exception)) { cardname }
  94. end
  95. 1 def standard_errors heading=nil
  96. 3 alert "warning", true do
  97. [
  98. 3 (wrap_with(:h4, heading, class: "alert-heading error") if heading),
  99. error_messages.join("<hr>")
  100. ]
  101. end
  102. end
  103. 1 def error_messages
  104. 3 card.errors.map do |attrib, msg|
  105. 3 attrib == :abort ? h(msg) : standard_error_message(attrib, msg)
  106. end
  107. end
  108. 1 def standard_error_message attribute, message
  109. 3 "<p><strong>#{h attribute.to_s.upcase}:</strong> #{h message}</p>"
  110. end
  111. 1 def not_found_errors
  112. 2 if card.errors.any?
  113. 1 standard_errors
  114. else
  115. 1 haml :not_found
  116. end
  117. end
  118. 1 def sign_in_or_up_links to_task
  119. 6 return if Auth.signed_in?
  120. 6 links = [signin_link, signup_link].compact.join " #{tr :or} "
  121. 6 wrap_with(:div) do
  122. 6 [tr(:please), links, to_task].join(" ") + "."
  123. end
  124. end
  125. 1 def signin_link
  126. 6 link_to_card :signin, tr(:sign_in),
  127. class: "signin-link", slotter: true, path: { view: :open }
  128. end
  129. 1 def signup_link
  130. 6 return unless signup_ok?
  131. 6 link_to_card :signup, tr(:sign_up),
  132. class: "signup-link", slotter: true, path: { action: :new }
  133. end
  134. 1 def signup_ok?
  135. 6 Card.new(type_id: Card::SignupID).ok? :create
  136. end
  137. 1 def quiet_denial
  138. wrap_with :span, class: "denied" do
  139. "<!-- Sorry, you don't have permission (#{@denied_task}) -->"
  140. end
  141. end
  142. 1 def loud_denial
  143. 5 voo.hide :menu
  144. 5 frame do
  145. 5 [wrap_with(:h1, tr(:sorry)),
  146. wrap_with(:div, loud_denial_message)]
  147. end
  148. end
  149. 1 def loud_denial_message
  150. 5 to_task = @denied_task ? tr(:denied_task, denied_task: @denied_task) : tr(:to_do_that)
  151. case
  152. 5 when not_denied_task_read?
  153. tr(:read_only)
  154. when Auth.signed_in?
  155. 1 tr(:need_permission_task, task: to_task)
  156. else
  157. 4 Env.save_interrupted_action request.env["REQUEST_URI"]
  158. 4 sign_in_or_up_links to_do_unauthorized_task
  159. end
  160. end
  161. 1 def not_denied_task_read?
  162. 5 @denied_task != :read && Card.config.read_only
  163. end
  164. 1 def to_do_unauthorized_task
  165. 4 @denied_task ? tr(:denied_task, denied_task: @denied_task) : tr(:to_do_that)
  166. end
  167. end
  168. end;end;end;end;end;
  169. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/error.rb ~~

card/tmpsets/set/mod010-standard/all/rich_html/frame.rb

96.97% lines covered

33 relevant lines. 32 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module RichHtml;
  3. # Set: All cards (RichHtml, Frame)
  4. #
  5. 1 module Frame;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/frame.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :flash, cache: :never, unknown: true, perms: :none do
  10. 20 flash_notice = params[:flash] || Env.success.flash
  11. 20 return "" unless flash_notice.present? && focal?
  12. Array(flash_notice).join "\n"
  13. end
  14. 1 def frame &block
  15. 20 standard_frame &block
  16. end
  17. 1 def standard_frame slot=true
  18. 20 with_frame slot do
  19. 39 wrap_body { yield } if block_given?
  20. end
  21. end
  22. 1 def with_frame slot=true, header=frame_header, slot_opts={}
  23. 20 voo.hide :help
  24. 20 add_name_context
  25. 20 wrap slot, slot_opts do
  26. 20 panel do
  27. 20 [header, frame_help, render_flash, (yield if block_given?)]
  28. end
  29. end
  30. end
  31. 1 def frame_header
  32. 20 _render_header
  33. end
  34. 1 def frame_help
  35. 20 with_class_up "help-text", "alert alert-info" do
  36. 20 _render :help
  37. end
  38. end
  39. 1 def frame_and_form action, form_opts={}
  40. 8 form_opts ||= {}
  41. 8 frame do
  42. 8 card_form action, form_opts do
  43. 8 yield
  44. end
  45. end
  46. end
  47. 1 def panel
  48. 20 wrap_with :div, class: classy("d0-card-frame") do
  49. 20 yield
  50. end
  51. end
  52. end
  53. end;end;end;end;end;
  54. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/frame.rb ~~

card/tmpsets/set/mod010-standard/all/rich_html/header.rb

88.89% lines covered

36 relevant lines. 32 lines covered and 4 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module RichHtml;
  3. # Set: All cards (RichHtml, Header)
  4. #
  5. 1 module Header;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/header.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :header, perms: :none do
  10. 20 main_header
  11. end
  12. 1 def main_header
  13. 20 header_wrap _render_header_title
  14. end
  15. 1 def header_wrap content=nil
  16. 20 haml :header_wrap, content: (block_given? ? yield : output(content))
  17. end
  18. 1 view :header_title, perms: :none do
  19. 20 header_title_elements
  20. end
  21. 1 def header_title_elements
  22. 20 voo.hide :title_toggle if show_view?(:icon_toggle, :hide)
  23. 20 title_view = show_view?(:title_toggle, :hide) ? :title_toggle : :title
  24. 20 [_render_icon_toggle(optional: :hide), _render(title_view)]
  25. end
  26. 1 def show_draft_link?
  27. card.drafts.present? && @slot_view == :edit
  28. end
  29. 1 view :title_toggle, perms: :none do
  30. 5 content_toggle(_render_title(hide: :title_link))
  31. end
  32. 1 view :icon_toggle, perms: :none do
  33. direction = @toggle_mode == :close ? :expand : :collapse_down
  34. content_toggle icon_tag(direction)
  35. end
  36. 1 view :toggle, :icon_toggle # deprecated; use icon_toggle
  37. 1 def content_toggle text=""
  38. 5 return if text.nil?
  39. 5 verb, adjective = toggle_verb_adjective
  40. 5 link_to_view adjective, text, title: "#{verb} #{card.name}", # LOCALIZE
  41. class: "toggle-#{adjective} toggler nodblclick"
  42. end
  43. 1 def toggle_view
  44. 20 toggle_verb_adjective.last
  45. end
  46. 1 TOGGLE_MAP = { close: %w[open open], open: %w[close closed] } # LOCALIZE first item
  47. 1 def toggle_verb_adjective
  48. 25 TOGGLE_MAP[@toggle_mode || :open] ||
  49. raise(Card::Error, "invalid toggle mode: #{@toggle_mode}")
  50. end
  51. 1 def structure_editable?
  52. card.structure && card.template.ok?(:update)
  53. end
  54. end
  55. end;end;end;end;end;
  56. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/header.rb ~~

card/tmpsets/set/mod010-standard/all/rich_html/html_views/guide.rb

81.82% lines covered

33 relevant lines. 27 lines covered and 6 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 5 class Card; module Set; class All; module RichHtml;; module HtmlViews;
  3. # Set: All cards (RichHtml, HtmlViews, Guide)
  4. #
  5. 1 module Guide;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/html_views/guide.rb"; end
  8. 1 def guide_card
  9. 20 guide_card = rule_card(:guide)
  10. 20 return unless guide_card
  11. 20 guide_card = guide_card.first_card if guide_card.type_id == Card::PointerID
  12. 20 guide_card if guide_card.ok?(:read)
  13. end
  14. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  15. 1 view :guide, unknown: true, cache: :never, wrap: :slot do
  16. guide
  17. end
  18. 1 def guide
  19. 10 guide_text = rule_based_guide
  20. 10 return "" unless guide_text.present?
  21. 10 if (rule_card = card.help_rule_card)
  22. edit_link = with_nest_mode(:normal) { nest(rule_card, view: :edit_link) }
  23. guide_text = "<span class='d-none'>#{edit_link}</span>#{guide_text}"
  24. end
  25. 10 wrap_with :div, guide_text, class: classy("guide-text")
  26. end
  27. 1 def alert_guide
  28. 8 guide_text = guide
  29. 8 return "" unless guide_text.present?
  30. 16 alert(:secondary, true, false, class: "guide") { guide_text }
  31. end
  32. 1 def raw_guide_text
  33. 10 false
  34. end
  35. 1 def rule_based_guide
  36. 10 if raw_guide_text
  37. with_nest_mode :normal do
  38. process_content raw_guide_text, chunk_list: :references
  39. # render guide text with current card's format
  40. # so current card's context is used in guide card nests
  41. end
  42. 10 elsif card.guide_card
  43. 10 with_nest_mode :normal do
  44. 10 nest card.guide_card, view: :core
  45. end
  46. else
  47. ""
  48. end
  49. end
  50. end
  51. end;end;end;end;end;end;
  52. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/html_views/guide.rb ~~

card/tmpsets/set/mod010-standard/all/rich_html/html_views/help.rb

77.42% lines covered

31 relevant lines. 24 lines covered and 7 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 5 class Card; module Set; class All; module RichHtml;; module HtmlViews;
  3. # Set: All cards (RichHtml, HtmlViews, Help)
  4. #
  5. 1 module Help;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/html_views/help.rb"; end
  8. 1 def help_rule_card
  9. 30 help_card = rule_card(:help)
  10. 30 help_card if help_card&.ok?(:read)
  11. end
  12. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  13. 1 view :help, unknown: true, cache: :never, wrap: :slot do
  14. 8 help = help_text
  15. 8 return "" unless help.present?
  16. wrap_with :div, wrap_help_text(help), class: classy("help-text")
  17. end
  18. 1 view :help_text, unknown: true, cache: :never do
  19. 6 wrap_help_text help_text
  20. end
  21. 1 def wrap_help_text text
  22. 6 help = text
  23. 6 if (rule_card = card.help_rule_card)
  24. edit_link = with_nest_mode(:normal) { nest(rule_card, view: :edit_link) }
  25. help = "<span class='d-none'>#{edit_link}</span>#{text}"
  26. end
  27. 6 help
  28. end
  29. 1 view :lead do
  30. class_up "card-slot", "lead"
  31. _view_content
  32. end
  33. 1 def help_text
  34. 14 voo.help || rule_based_help
  35. end
  36. 1 def raw_help_text
  37. 14 card.try(:raw_help_text) || card.help_rule_card&.content
  38. end
  39. 1 def rule_based_help
  40. 14 return "" unless (help_text = raw_help_text)
  41. with_nest_mode :normal do
  42. process_content help_text, chunk_list: :references
  43. # render help card with current card's format
  44. # so current card's context is used in help card nests
  45. end
  46. end
  47. end
  48. end;end;end;end;end;end;
  49. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/html_views/help.rb ~~

card/tmpsets/set/mod010-standard/all/rich_html/html_views/info.rb

38.1% lines covered

42 relevant lines. 16 lines covered and 26 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 5 class Card; module Set; class All; module RichHtml;; module HtmlViews;
  3. # Set: All cards (RichHtml, HtmlViews, Info)
  4. #
  5. 1 module Info;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/html_views/info.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :type, unknown: true do
  10. 5 link_to_card card.type_card, nil, class: "cardtype"
  11. end
  12. 1 view :change do
  13. voo.show :title_link
  14. voo.hide :menu
  15. wrap do
  16. [_render_title,
  17. _render_menu,
  18. _render_last_action]
  19. end
  20. end
  21. 1 view :last_action do
  22. act = card.last_act
  23. return unless act
  24. action = act.action_on card.id
  25. return unless action
  26. action_verb =
  27. case action.action_type
  28. when :create then "added"
  29. when :delete then "deleted"
  30. else
  31. link_to_view :history, "edited", class: "last-edited", rel: "nofollow"
  32. end
  33. %(
  34. <span class="last-update">
  35. #{action_verb} #{_render_acted_at} ago by
  36. #{subformat(card.last_actor)._render_link}
  37. </span>
  38. )
  39. end
  40. 1 view :type_info do
  41. return unless card.type_code != :basic
  42. wrap_with :span, class: "type-info float-right" do
  43. link_to_card card.type_name, nil, class: "navbar-link"
  44. end
  45. end
  46. 1 view :view_list do
  47. %i[bar box info_bar open closed titled labeled content content_panel].map do |v|
  48. wrap_with :p, [content_tag(:h3, v), render(v, show: :menu)]
  49. end.flatten.join ""
  50. end
  51. 1 view :demo do
  52. frame do
  53. [
  54. view_select,
  55. wrap_with(:div, view_demo, class: "demo-slot")
  56. ]
  57. end
  58. end
  59. 1 def demo_view
  60. Env.params[:demo_view] || :core
  61. end
  62. 1 def view_demo
  63. wrap(true) do
  64. render demo_view
  65. end
  66. end
  67. 1 def view_select
  68. card_form :get, success: { view: :demo } do
  69. select_tag :demo_view, options_for_select(all_views, demo_view),
  70. class: "_submit-on-select"
  71. end
  72. end
  73. 1 def all_views
  74. Card::Set::Format::AbstractFormat::ViewDefinition.views
  75. .slice(*self.class.ancestors)
  76. .values.map(&:keys).flatten.uniq
  77. end
  78. end
  79. end;end;end;end;end;end;
  80. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/html_views/info.rb ~~

card/tmpsets/set/mod010-standard/all/rich_html/html_views/size.rb

61.54% lines covered

13 relevant lines. 8 lines covered and 5 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 5 class Card; module Set; class All; module RichHtml;; module HtmlViews;
  3. # Set: All cards (RichHtml, HtmlViews, Size)
  4. #
  5. 1 module Size;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/html_views/size.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 SIZE_IN_PX = { icon: 16, small: 75, medium: 200, large: 500 }.freeze
  10. # used to control size of svg
  11. 1 view :max_size do
  12. if voo.size.is_a?(String) && voo.size.match(/^\d+x\d+\$/)
  13. max_size(*voo.size.split("x"))
  14. else
  15. px = SIZE_IN_PX[voo.size&.to_sym] || 200
  16. max_size px, px
  17. end
  18. end
  19. 1 def max_size w, h
  20. "max-width: #{w}px; max-height: #{h}px"
  21. end
  22. end
  23. end;end;end;end;end;end;
  24. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/html_views/size.rb ~~

card/tmpsets/set/mod010-standard/all/rich_html/menu.rb

78.57% lines covered

70 relevant lines. 55 lines covered and 15 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module RichHtml;
  3. # Set: All cards (RichHtml, Menu)
  4. #
  5. 1 module Menu;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/menu.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :menu, denial: :blank, unknown: true do
  10. 13 return "" if card.unknown?
  11. 6 wrap_with :div, class: "card-menu #{menu_link_classes}" do
  12. 6 [render_help_link,
  13. menu_link,
  14. 6 (voo.show?(:bridge_link) ? bridge_link(false) : nil)]
  15. end
  16. end
  17. 1 def menu_link
  18. 6 case voo.edit
  19. when :inline
  20. edit_inline_link
  21. when :full
  22. edit_in_bridge_link
  23. else # :standard
  24. 6 edit_link
  25. end
  26. end
  27. 1 def edit_view
  28. case voo.edit
  29. when :inline
  30. :edit_inline
  31. when :full
  32. :edit
  33. else # :standard
  34. edit_link
  35. end
  36. end
  37. 1 view :edit_link, unknown: true, denial: :blank do
  38. edit_link edit_link_view
  39. end
  40. 1 def edit_link_view
  41. :edit
  42. end
  43. 1 view :full_page_link do
  44. full_page_link
  45. end
  46. 1 view :bridge_link, unknown: true do
  47. bridge_link
  48. end
  49. 1 def bridge_link in_modal=true
  50. 6 opts = { class: "bridge-link" }
  51. 6 if in_modal
  52. # add_class opts, "close"
  53. opts["data-slotter-mode"] = "modal-replace"
  54. end
  55. 6 link_to_view :bridge, material_icon(:more_horiz), opts
  56. end
  57. # no caching because help_text view doesn't cache, and we can't have a
  58. # stub in the data-content attribute or it will get html escaped.
  59. 1 view :help_link, cache: :never, unknown: true do
  60. 6 help_link render_help_text, help_title
  61. end
  62. 1 def help_link text=nil, title=nil
  63. 6 opts = help_popover_opts text, title
  64. 6 add_class opts, "_card-menu-popover"
  65. 6 link_to help_icon, opts
  66. end
  67. 1 def help_popover_opts text=nil, title=nil
  68. 6 text ||= render_help_text
  69. 6 opts = { "data-placement": :left, class: "help-link" }
  70. 6 popover_opts text, title, opts
  71. end
  72. 1 def help_icon
  73. 6 material_icon("help")
  74. end
  75. 1 def help_title
  76. 6 "#{name_parts_links} (#{render_type}) #{full_page_link unless card.simple?}"
  77. end
  78. 1 def name_parts_links
  79. 6 card.name.parts.map do |part|
  80. 6 link_to_card part
  81. end.join Card::Name.joint
  82. end
  83. 1 def full_page_link
  84. link_to_card full_page_card, full_page_icon, class: classy("full-page-link")
  85. end
  86. 1 def full_page_card
  87. card
  88. end
  89. 1 def edit_in_bridge_link opts={}
  90. edit_link :bridge, opts
  91. end
  92. 1 def edit_link view=:edit, opts={}
  93. 6 link_to_view view, opts.delete(:link_text) || menu_icon,
  94. edit_link_opts(opts.reverse_merge(modal: :lg))
  95. end
  96. # @param modal [Symbol] modal size
  97. 1 def edit_link_opts modal: nil
  98. 6 opts = { class: classy("edit-link") }
  99. 6 if modal
  100. 6 opts[:"data-slotter-mode"] = "modal"
  101. 6 opts[:"data-modal-class"] = "modal-#{modal}"
  102. end
  103. 6 opts
  104. end
  105. 1 def menu_link_classes
  106. 6 "nodblclick" + (show_view?(:hover_link) ? " _show-on-hover" : "")
  107. end
  108. 1 def menu_icon
  109. 6 material_icon "edit"
  110. end
  111. 1 def full_page_icon
  112. icon_tag :open_in_new
  113. end
  114. end
  115. end;end;end;end;end;
  116. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/menu.rb ~~

card/tmpsets/set/mod010-standard/all/rich_html/modal.rb

73.85% lines covered

65 relevant lines. 48 lines covered and 17 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module RichHtml;
  3. # Set: All cards (RichHtml, Modal)
  4. #
  5. 1 module Modal;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/modal.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 MODAL_SIZE = { small: "sm", medium: nil, large: "lg", full: "full" }.freeze
  10. 1 MODAL_CLOSE_OPTS = { "data-dismiss": "modal",
  11. "data-cy": "close-modal" }.freeze
  12. 1 wrapper :modal do |opts={}|
  13. 1 haml :modal_dialog, body: interior,
  14. classes: modal_dialog_classes(opts),
  15. title: normalize_modal_option(:title, opts),
  16. menu: normalize_modal_option(:menu, opts),
  17. footer: normalize_modal_option(:footer, opts)
  18. end
  19. 1 def normalize_modal_option key, opts
  20. 3 val = opts[key]
  21. 3 return render("modal_#{key}") unless val
  22. 1 cast_model_option val
  23. end
  24. 1 def cast_model_option val
  25. 2 case val
  26. when Symbol
  27. cast_model_option_symbol val
  28. when Proc
  29. val.call(self)
  30. else
  31. 2 val
  32. end
  33. end
  34. 1 def cast_model_option_symbol val
  35. respond_to?(val) ? send(val) : val
  36. end
  37. 1 view :modal, wrap: :modal do
  38. ""
  39. end
  40. 1 def show_in_modal_link link_text, body
  41. link_to_view :modal, link_text, "data-modal-body": body, "data-slotter-mode": "modal"
  42. end
  43. 1 def modal_close_button link_text="Close", opts={}
  44. classes = opts.delete(:class)
  45. button_opts = opts.merge(MODAL_CLOSE_OPTS)
  46. add_class button_opts, classes if classes
  47. button_tag link_text, button_opts
  48. end
  49. 1 def modal_submit_button opts={}
  50. add_class opts, "submit-button _close-modal"
  51. submit_button opts
  52. end
  53. 1 view :modal_menu, unknown: true, wrap: :modal_menu do
  54. 1 [close_modal_window, pop_out_modal_window]
  55. end
  56. 1 wrapper :modal_menu, :div, class: "modal-menu ml-auto"
  57. 1 view :modal_title, unknown: true do
  58. ""
  59. end
  60. 1 view :modal_footer, unknown: true do
  61. button_tag "Close",
  62. class: "btn-xs _close-modal float-right",
  63. "data-dismiss" => "modal"
  64. end
  65. 1 view :modal_link do
  66. modal_link _render_title, size: voo.size
  67. end
  68. 1 def modal_link text=nil, opts={}
  69. opts = modal_link_opts(opts)
  70. opts[:path][:layout] ||= :modal
  71. link_to text, opts
  72. end
  73. 1 def modal_link_opts opts
  74. 1 add_class opts, "slotter"
  75. 1 opts.reverse_merge! path: {},
  76. "data-slotter-mode": "modal",
  77. "data-modal-class": modal_dialog_classes(opts),
  78. remote: true
  79. 1 opts
  80. end
  81. 1 def modal_dialog_classes opts
  82. 2 classes = [classy("modal-dialog")]
  83. 2 return classes unless opts.present?
  84. 2 add_modal_size_class classes, opts[:size]
  85. 2 classes << "modal-dialog-centered" if opts[:vertically_centered]
  86. 2 classes.join " "
  87. end
  88. 1 def add_modal_size_class classes, size
  89. 2 size = normalize_modal_size_class size
  90. 2 return if size == :medium || size.blank?
  91. 1 classes << "modal-#{MODAL_SIZE[size]}"
  92. end
  93. 1 def normalize_modal_size_class size
  94. 2 size.in?(MODAL_SIZE.keys) ? size : cast_model_option(size)
  95. end
  96. 1 def close_modal_window
  97. 1 link_to icon_tag(:close), path: "",
  98. class: "_close-modal close",
  99. "data-dismiss": "modal"
  100. end
  101. 1 def pop_out_modal_window
  102. 1 link_to icon_tag(:new_window), path: {}, class: "pop-out-modal close"
  103. end
  104. end
  105. end;end;end;end;end;
  106. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/modal.rb ~~

card/tmpsets/set/mod010-standard/all/rich_html/overlay.rb

37.1% lines covered

62 relevant lines. 23 lines covered and 39 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module RichHtml;
  3. # Set: All cards (RichHtml, Overlay)
  4. #
  5. 1 module Overlay;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/overlay.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 OVERLAY_CLOSE_OPTS = { class: "_close-overlay btn-sm",
  10. "data-dismiss": "overlay",
  11. type: "button" }.freeze
  12. 1 wrapper :overlay do |opts|
  13. class_up "card-slot", "_overlay d0-card-overlay bg-body"
  14. @content_body = true
  15. voo.hide! :menu
  16. overlay_frame true, overlay_header(opts[:title]), opts[:slot] do
  17. interior
  18. end
  19. end
  20. 1 view :overlay_header, unknown: true do
  21. overlay_header
  22. end
  23. 1 view :overlay_title do
  24. _render_title
  25. end
  26. 1 view :overlay_menu do
  27. wrap_with :div, class: "btn-group btn-group-sm align-self-start ml-auto" do
  28. [render_overlay_help_link, slotify_overlay_link, close_overlay_link]
  29. end
  30. end
  31. 1 view :overlay_help_link, cache: :never, unknown: true do
  32. opts = help_popover_opts
  33. add_open_guide_opts opts
  34. overlay_menu_link "question-circle", opts
  35. end
  36. 1 def add_open_guide_opts opts
  37. return unless card.guide_card
  38. slot_selector = ".bridge-sidebar > ._overlay-container-placeholder > .card-slot"
  39. opts.merge! remote: true,
  40. href: path(mark: card, view: :overlay_guide),
  41. "data-slot-selector": slot_selector,
  42. "data-slotter-mode": "overlay"
  43. add_class opts, "slotter"
  44. end
  45. 1 def slotify_overlay_link
  46. overlay_menu_link "external-link-square", card: card
  47. end
  48. 1 def close_overlay_link
  49. overlay_menu_link :close, path: "#", "data-dismiss": "overlay"
  50. end
  51. 1 def overlay_close_button link_text="Close", opts={}
  52. classes = opts.delete(:class)
  53. button_opts = opts.merge(OVERLAY_CLOSE_OPTS)
  54. add_class button_opts, classes if classes
  55. button_tag link_text, button_opts
  56. end
  57. 1 def overlay_delete_button
  58. opts = { no_success: true }.merge OVERLAY_CLOSE_OPTS
  59. delete_button opts
  60. end
  61. 1 def overlay_save_and_close_button
  62. submit_button text: "Save and Close", class: "_close-on-success",
  63. "data-cy": "submit-overlay"
  64. end
  65. 1 def overlay_menu_link icon, args={}
  66. add_class args, "border-light text-dark p-1 ml-1"
  67. button_link fa_icon(icon, class: "fa-lg"), args.merge(btn_type: "outline-secondary")
  68. end
  69. 1 def overlay_header title=nil
  70. title ||= _render_overlay_title
  71. class_up "d0-card-header", "bg-body"
  72. class_up "d0-card-header-title", "d-flex"
  73. header_wrap [title, _render_overlay_menu]
  74. end
  75. 1 def overlay_frame slot=true, header=render_overlay_header, slot_opts=nil
  76. slot_opts ||= {}
  77. overlay_framer slot, header, slot_opts do
  78. wrap_body { yield }
  79. end
  80. end
  81. 1 def haml_overlay_frame slot=true, header=render_overlay_header
  82. overlay_framer slot, header, {} do
  83. haml_wrap_body { yield }
  84. end
  85. end
  86. 1 private
  87. 1 def overlay_framer slot, header, slot_opts
  88. class_up "card-slot", "_overlay"
  89. with_frame slot, header, slot_opts do
  90. yield
  91. end
  92. end
  93. end
  94. end;end;end;end;end;
  95. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/overlay.rb ~~

card/tmpsets/set/mod010-standard/all/rich_html/process_layout.rb

72.09% lines covered

43 relevant lines. 31 lines covered and 12 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module RichHtml;
  3. # Set: All cards (RichHtml, ProcessLayout)
  4. #
  5. 1 module ProcessLayout;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/process_layout.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. # TODO: use CodeFile cards for these
  10. # builtin layouts allow for rescue / testing
  11. # HTML_LAYOUTS = Mod::Loader.load_layouts(:html).merge "none" => "{{_main}}"
  12. # HAML_LAYOUTS = Mod::Loader.load_layouts(:haml)
  13. 1 def show_with_page_layout view, args
  14. 23 main!
  15. 23 args = main_render_args view, args
  16. 23 if explicit_modal_wrapper?(view) && page_layout.to_sym != :modal
  17. render_outside_of_layout view, args
  18. else
  19. 23 render_with_layout view, page_layout, args
  20. end
  21. end
  22. 1 def main_render_args view, args
  23. 23 args[:view] = view if view
  24. 23 args[:main] = true
  25. 23 args[:main_view] = true
  26. 23 args
  27. end
  28. 1 def page_layout
  29. 23 params[:layout] || layout_name_from_rule || :default
  30. end
  31. 1 def render_with_layout view, layout, args={}
  32. 23 view_opts = Layout.main_nest_opts(layout, self)
  33. 23 view ||= view_opts.delete(:view) || default_nest_view
  34. 23 view_opts[:home_view] = view
  35. 23 view_opts[:layout] = layout
  36. 23 render! view, view_opts.reverse_merge(args)
  37. end
  38. 1 def render_outside_of_layout view, args
  39. body = render_with_layout(nil, page_layout, {})
  40. modal = render!(view, args)
  41. if body.include?("</body>")
  42. # a bit hacky
  43. # the problem is that the body tag has to be in the layout
  44. # so that you can add layout css classes like <body class="right-sidebar">
  45. body.sub!("</body>", "#{modal}</body>")
  46. else
  47. body += modal
  48. end
  49. body
  50. end
  51. 1 def show_layout?
  52. 276 !Env.ajax? || params[:layout]
  53. end
  54. 1 def explicit_modal_wrapper? view
  55. 23 return unless view_setting(:wrap, view)
  56. wrapper_names(view_setting(:wrap, view)).any? { |n| n == :modal || n == :bridge }
  57. end
  58. 1 def wrapper_names wrappers
  59. case wrappers
  60. when Hash then wrappers.keys
  61. when Array then wrappers.map { |w| w.is_a?(Array) ? w.first : w }
  62. else [wrappers]
  63. end
  64. end
  65. 1 def layout_name_from_rule
  66. 23 card.rule_card(:layout)&.try :item_name
  67. end
  68. end
  69. end;end;end;end;end;
  70. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/process_layout.rb ~~

card/tmpsets/set/mod010-standard/all/rich_html/show.rb

84.0% lines covered

25 relevant lines. 21 lines covered and 4 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module RichHtml;
  3. # Set: All cards (RichHtml, Show)
  4. #
  5. 1 module Show;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/show.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def show view, args
  10. 28 content = send show_method, view, args
  11. 28 show_full_page? ? wrap_with_html_page(content) : content
  12. # TODO: remove the following after tracking down wikirate encoding bug
  13. rescue Card::Error::ServerError => e
  14. if e.message.match?(/invalid byte sequence/)
  15. Card::Lexicon.cache.reset
  16. Rails.logger.info "reset name cache to prevent encoding freakiness"
  17. end
  18. raise e
  19. end
  20. 1 def show_method
  21. 28 "show_#{show_layout? ? :with : :without}_page_layout"
  22. end
  23. 1 def show_without_page_layout view, args
  24. 5 @main = true if params[:is_main] || args[:main]
  25. 5 args.delete(:layout)
  26. 5 view ||= args[:home_view] || :open # default_nest_view
  27. 5 render! view, args
  28. end
  29. 1 def show_full_page?
  30. 28 !Env.ajax?
  31. end
  32. 1 wrapper :html_page do
  33. 23 <<-HTML.strip_heredoc
  34. <!DOCTYPE HTML>
  35. <html class="h-100">
  36. <head>
  37. #{head_content}
  38. </head>
  39. #{interior}
  40. </html>
  41. HTML
  42. end
  43. 1 def head_content
  44. 23 nest card.rule_card(:head), view: :head_content
  45. end
  46. end
  47. end;end;end;end;end;
  48. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/show.rb ~~

card/tmpsets/set/mod010-standard/all/rich_html/title.rb

89.29% lines covered

28 relevant lines. 25 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module RichHtml;
  3. # Set: All cards (RichHtml, Title)
  4. #
  5. 1 module Title;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/title.rb"; end
  8. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  9. 1 view :title, compact: true, perms: :none do
  10. standard_title
  11. end
  12. 1 def standard_title
  13. 155 name_variant title_in_context(voo.title)
  14. end
  15. end
  16. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  17. 1 view :title do
  18. 155 show_view?(:title_link, :hide) ? render_title_link : render_title_no_link
  19. end
  20. 1 view :title_link, compact: true, perms: :none do
  21. link_to_card card.name, render_title_no_link
  22. end
  23. 1 view :title_no_link, compact: true, perms: :none do
  24. 155 wrapped_title standard_title
  25. end
  26. 1 def title_with_link link_text
  27. link_to_card card.name, link_text
  28. end
  29. 1 def safe_name
  30. 23 h super
  31. end
  32. 1 def title_in_context title=nil
  33. 155 title = title&.html_safe
  34. # escape titles generated from card names, but not those set explicitly
  35. 155 h super(title)
  36. end
  37. 1 def wrapped_title title
  38. 155 wrap_with :span, class: classy("card-title"), title: title do
  39. 155 title.to_name.parts.join wrapped_joint
  40. end
  41. end
  42. 1 def wrapped_joint
  43. 155 wrap_with :span, "+", classy("joint")
  44. end
  45. end
  46. end;end;end;end;end;
  47. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/title.rb ~~

card/tmpsets/set/mod010-standard/all/rich_html/wrapper.rb

86.59% lines covered

82 relevant lines. 71 lines covered and 11 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module RichHtml;
  3. # Set: All cards (RichHtml, Wrapper)
  4. #
  5. 1 module Wrapper;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/wrapper.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. # Does two main things:
  10. # (1) gives CSS classes for styling and
  11. # (2) adds card data for javascript - including the "card-slot" class,
  12. # which in principle is not supposed to be in styles
  13. 1 def wrap slot=true, slot_attr={}, tag=:div, &block
  14. 74 method_wrap :wrap_with, tag, slot, slot_attr, &block
  15. end
  16. 1 wrapper :slot do |opts|
  17. 20 class_up "card-slot", opts[:class] if opts[:class]
  18. 20 method_wrap :wrap_with, :div, true, opts do
  19. 20 interior
  20. end
  21. end
  22. 1 def haml_wrap slot=true, slot_attr={}, tag=:div, &block
  23. method_wrap :haml_tag, tag, slot, slot_attr, &block
  24. end
  25. 1 def method_wrap method, tag, slot, slot_attr, &block
  26. 94 @slot_view = @current_view
  27. 94 debug_slot do
  28. 94 send method, tag, slot_attributes(slot, slot_attr), &block
  29. end
  30. end
  31. 1 def slot_attributes slot, slot_attr
  32. 94 { id: slot_id, class: wrap_classes(slot), data: wrap_data }.tap do |hash|
  33. 94 add_class hash, slot_attr.delete(:class)
  34. 94 hash.deep_merge! slot_attr
  35. end
  36. end
  37. 1 def slot_id
  38. 94 "#{card.name.safe_key}-#{@current_view}-view"
  39. end
  40. 1 def wrap_data slot=true
  41. 94 with_slot_data slot do
  42. 94 { "card-id": card.id, "card-name": h(card.name),
  43. "slot-id": SecureRandom.hex(10) }
  44. end
  45. end
  46. 1 def with_slot_data slot
  47. 94 hash = yield
  48. # rails helper convert slot hash to json
  49. # but haml joins nested keys with a dash
  50. 94 hash[:slot] = slot_options_json if slot
  51. 94 hash
  52. end
  53. 1 def slot_options_json
  54. 94 html_escape_except_quotes JSON(slot_options)
  55. end
  56. 1 def slot_options
  57. 94 options = voo ? voo.slot_options : {}
  58. 94 name_context_slot_option options
  59. 94 options
  60. end
  61. 1 def name_context_slot_option opts
  62. 94 return unless initial_context_names.present?
  63. 2 opts[:name_context] = initial_context_names.map(&:key) * ","
  64. end
  65. 1 def debug_slot
  66. 94 debug_slot? ? debug_slot_wrap { yield } : yield
  67. end
  68. 1 def debug_slot?
  69. 94 params[:debug] == "slot"
  70. end
  71. 1 def debug_slot_wrap
  72. pre = "<!--\n\n#{' ' * depth}"
  73. post = " SLOT: #{h card.name}\n\n-->"
  74. [pre, "BEGIN", post, yield, pre, "END", post].join
  75. end
  76. 1 def wrap_classes slot
  77. 94 list = slot ? ["card-slot"] : []
  78. 94 list += ["#{@current_view}-view", card.safe_set_keys]
  79. 94 list << "STRUCTURE-#{voo.structure.to_name.key}" if voo&.structure
  80. 94 classy list
  81. end
  82. 1 def wrap_body
  83. 38 wrap_with(:div, class: body_css_classes) { yield }
  84. end
  85. 1 def haml_wrap_body
  86. wrap_body do
  87. capture_haml { yield }
  88. end
  89. end
  90. 1 def body_css_classes
  91. 19 css_classes = ["d0-card-body"]
  92. 19 css_classes += ["d0-card-content", card.safe_set_keys] if @content_body
  93. 19 classy(*css_classes)
  94. end
  95. 1 def wrap_main
  96. 23 return yield if no_main_wrap?
  97. 23 wrap_with :div, yield, id: "main"
  98. end
  99. 1 def no_main_wrap?
  100. 23 Env.ajax? || params[:layout] == "none"
  101. end
  102. 1 def wrap_with tag, content_or_args={}, html_args={}
  103. 1362 content = block_given? ? yield : content_or_args
  104. 1342 tag_args = block_given? ? content_or_args : html_args
  105. 2684 content_tag(tag, tag_args) { output(content).to_s.html_safe }
  106. end
  107. 1 def wrap_each_with tag, content_or_args={}, args={}
  108. content = block_given? ? yield(args) : content_or_args
  109. args = block_given? ? content_or_args : args
  110. content.compact.map do |item|
  111. wrap_with(tag, args) { item }
  112. end.join "\n"
  113. end
  114. 1 private
  115. 1 def html_escape_except_quotes string
  116. # to be used inside single quotes (makes for readable json attributes)
  117. 94 string.to_s.gsub(/&/, "&amp;")
  118. .gsub(/\'/, "&apos;")
  119. .gsub(/>/, "&gt;")
  120. .gsub(/</, "&lt;")
  121. end
  122. 1 wrapper :div, :div
  123. 1 wrapper :em, :em
  124. 1 wrapper :none do
  125. interior
  126. end
  127. end
  128. end;end;end;end;end;
  129. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/all/rich_html/wrapper.rb ~~

card/tmpsets/set/mod010-standard/right/discussion.rb

60.0% lines covered

10 relevant lines. 6 lines covered and 4 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Discussion" cards
  4. #
  5. 1 module Discussion;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/right/discussion.rb"; end
  8. 1 view :titled, unknown: true do
  9. voo.show :comment_box
  10. super()
  11. end
  12. 1 view :open, unknown: true do
  13. voo.show :comment_box
  14. super()
  15. end
  16. end;end;end;end;
  17. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/right/discussion.rb ~~

card/tmpsets/set/mod010-standard/right/head.rb

84.62% lines covered

13 relevant lines. 11 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Head" cards
  4. #
  5. 1 module Head;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/right/head.rb"; end
  8. 1 def ok_to_read
  9. 23 true
  10. end
  11. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  12. 1 view :head_content do
  13. 23 process_content render_raw
  14. end
  15. 1 view :one_line_content do
  16. raw_one_line_content
  17. end
  18. 1 view :core do
  19. process_content ::CodeRay.scan(render_raw, :html).div
  20. end
  21. end
  22. end;end;end;end;
  23. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/right/head.rb ~~

card/tmpsets/set/mod010-standard/right/type_plus_right.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+TypePlusRight" cards
  4. #
  5. 1 module TypePlusRight;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/right/type_plus_right.rb"; end
  8. 1 def related_sets _with_self=false
  9. [[name, Card::Set::TypePlusRight.label(name.left)],
  10. ["#{name[1]}+*right", Card::Set::Right.label(name[1])]]
  11. end
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/right/type_plus_right.rb ~~

card/tmpsets/set/mod010-standard/right/when_created.rb

71.43% lines covered

7 relevant lines. 5 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+WhenCreated" cards
  4. #
  5. 1 module WhenCreated;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/right/when_created.rb"; end
  8. 1 def content
  9. return "" unless left&.real?
  10. I18n.localize left.created_at, format: :card_dayofwk_min_tz
  11. end
  12. # view :core, :raw
  13. end;end;end;end;
  14. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/right/when_created.rb ~~

card/tmpsets/set/mod010-standard/right/when_last_edited.rb

71.43% lines covered

7 relevant lines. 5 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+WhenLastEdited" cards
  4. #
  5. 1 module WhenLastEdited;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/right/when_last_edited.rb"; end
  8. 1 def content
  9. return "" unless left&.real?
  10. I18n.localize left.updated_at, format: :card_dayofwk_min_tz
  11. end
  12. # view :core, :raw
  13. end;end;end;end;
  14. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/right/when_last_edited.rb ~~

card/tmpsets/set/mod010-standard/self/alerts.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Alerts"
  4. #
  5. 1 module Alerts;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/self/alerts.rb"; end
  8. 1 def content
  9. "<!-- *alerts is deprecated. please remove from layout -->"
  10. end
  11. # view :core, :raw
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/self/alerts.rb ~~

card/tmpsets/set/mod010-standard/self/cardtype.rb

52.63% lines covered

19 relevant lines. 10 lines covered and 9 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Cardtype"
  4. #
  5. 1 module Cardtype;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/self/cardtype.rb"; end
  8. GROUP = {
  9. 1 "Text" => %w[RichText PlainText Markdown Phrase HTML],
  10. "Data" => %w[Number Toggle Date URI],
  11. "Upload" => %w[File Image],
  12. "Custom" => [],
  13. "Organize" => ["List", "Pointer", "Search", "Link list", "Nest list",
  14. "Mirror List", "Mirrored List"],
  15. "Template" => ["Notification template", "Email template", "Twitter template"],
  16. "Admin" => ["Cardtype", "User", "Role", "Sign up", "Session", "Set", "Setting"],
  17. "Styling" => ["Layout", "Skin", "Bootswatch skin", "Customized bootswatch skin", "CSS", "SCSS"],
  18. "Scripting" => %w[JSON JavaScript CoffeeScript]
  19. }.freeze
  20. #DEFAULT_RULE_GROUPS = ["Text", "Data", "Upload", "Organize - Search"]
  21. #STRUCTURE_RULE_GROUPS = ["Text", "Organize > Search"]
  22. # group for each cardtype: { "RichText => "Content", "Layout" => "Admin", ... }
  23. 1 GROUP_MAP = GROUP.each_with_object({}) do |(cat, types), h|
  24. 46 types.each { |t| h[t] = cat }
  25. end
  26. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  27. 1 view :grouped_list do
  28. GROUP.keys.map do |group|
  29. type_list = group == "Custom" ? custom_types : GROUP[group]
  30. next if type_list.empty?
  31. [wrap_with(:h5, group), wrap_with(:p, listing(type_list))]
  32. end.flatten.join "\n"
  33. end
  34. 1 def custom_types
  35. custom_types = []
  36. Card.search(type_id: Card::CardtypeID, return: "name").each do |name|
  37. next if ::Card::Set::Self::Cardtype::GROUP_MAP[name]
  38. custom_types << name
  39. end
  40. custom_types
  41. end
  42. end
  43. end;end;end;end;
  44. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/self/cardtype.rb ~~

card/tmpsets/set/mod010-standard/self/codenames.rb

100.0% lines covered

4 relevant lines. 4 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Codenames"
  4. #
  5. 1 module Codenames;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/self/codenames.rb"; end
  8. end;end;end;end;
  9. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/self/codenames.rb ~~

card/tmpsets/set/mod010-standard/self/foot.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Foot"
  4. #
  5. 1 module Foot;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/self/foot.rb"; end
  8. 1 def content
  9. "<!-- *foot is deprecated. please remove from layout -->"
  10. end
  11. # view :core, :raw
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/self/foot.rb ~~

card/tmpsets/set/mod010-standard/self/home.rb

88.89% lines covered

9 relevant lines. 8 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Home"
  4. #
  5. 1 module Home;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/self/home.rb"; end
  8. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  9. 1 view :home_url, perms: :none do
  10. card_url ""
  11. end
  12. 1 view :home_path, perms: :none do
  13. 46 card_path ""
  14. end
  15. end
  16. end;end;end;end;
  17. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/self/home.rb ~~

card/tmpsets/set/mod010-standard/self/now.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Now"
  4. #
  5. 1 module Now;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/self/now.rb"; end
  8. 1 def content
  9. I18n.localize(Time.now, format: :card_dayofwk_min_tz)
  10. end
  11. # view :core, :raw
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/self/now.rb ~~

card/tmpsets/set/mod010-standard/self/sidebar.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Sidebar"
  4. #
  5. 1 module Sidebar;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/self/sidebar.rb"; end
  8. 1 def raw_help_text
  9. <<-TEXT
  10. Sidebar content of [[Layouts]] with sidebar. [[http://decko.org/sidebar|more]]
  11. TEXT
  12. end
  13. end;end;end;end;
  14. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/self/sidebar.rb ~~

card/tmpsets/set/mod010-standard/type/basic.rb

39.02% lines covered

41 relevant lines. 16 lines covered and 25 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Basic" cards
  4. #
  5. 1 module Basic;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/type/basic.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :open_content do
  10. 2 with_table_of_contents _render_core
  11. end
  12. 1 view :titled_content do
  13. with_table_of_contents _render_core
  14. end
  15. 1 def with_table_of_contents content
  16. 2 table_of_contents(content) || content
  17. end
  18. 1 def table_of_contents content
  19. 2 return if nest_mode == :compact || !content.present?
  20. 1 min = card.rule(:table_of_contents).to_i
  21. 1 return unless min && min > 0
  22. toc = toc_items content
  23. if toc.flatten.length >= min
  24. content.replace(
  25. %( <div class="table-of-contents"> <h5>#{tr(:toc)}</h5> ) +
  26. make_table_of_contents_list(toc) + "</div>" + content
  27. )
  28. end
  29. end
  30. 1 def toc_items content
  31. toc = []
  32. dep = 1
  33. content.gsub!(/<(h\d)>(.*?)<\/h\d>/i) do |match|
  34. if $LAST_MATCH_INFO
  35. tag, value = $LAST_MATCH_INFO[1, 2]
  36. value = strip_tags(value).strip
  37. next if value.empty?
  38. item = { value: value, uri: URI.escape(value) }
  39. case tag.downcase
  40. when "h1"
  41. item[:depth] = dep = 1
  42. toc << item
  43. when "h2"
  44. toc << [] if dep == 1
  45. item[:depth] = dep = 2
  46. toc.last << item
  47. end
  48. %(<a name="#{item[:uri]}"></a>#{match})
  49. end
  50. end
  51. toc
  52. end
  53. 1 def make_table_of_contents_list items
  54. list = items.map do |i|
  55. if i.is_a?(Array)
  56. make_table_of_contents_list(i)
  57. else
  58. %(<li><a href="##{i[:uri]}"> #{i[:value]}</a></li>)
  59. end
  60. end.join("\n")
  61. "<ol>" + list + "</ol>"
  62. end
  63. end
  64. end;end;end;end;
  65. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/type/basic.rb ~~

card/tmpsets/set/mod010-standard/type/cardtype.rb

70.27% lines covered

74 relevant lines. 52 lines covered and 22 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Cardtype" cards
  4. #
  5. 1 module Cardtype;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/type/cardtype.rb"; end
  8. 1 include_set Abstract::CqlSearch
  9. 1 def cql_content
  10. { type_id: id, sort: :name }
  11. end
  12. 1 def related_sets with_self=false
  13. sets = []
  14. sets << ["#{name}+*type", Card::Set::Type.label(name)] if known?
  15. sets + super
  16. end
  17. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  18. 1 view :type, unknown: true do
  19. 1 link_to_card card.type_card, nil, class: "cardtype"
  20. end
  21. 1 def type_formgroup args={}
  22. if card.cards_of_type_exist?
  23. wrap_with :div, tr(:cards_exist, cardname: safe_name)
  24. else
  25. super
  26. end
  27. end
  28. 1 view :add_link do
  29. add_link
  30. end
  31. 1 view :add_button do
  32. 1 add_link class: "btn btn-secondary"
  33. end
  34. 1 def add_link opts={}
  35. 1 voo.title ||= tr(:add_card, cardname: safe_name)
  36. 1 link_to render_title, add_link_opts(opts)
  37. end
  38. 1 def add_link_opts opts
  39. 1 modal = opts.delete :modal
  40. 1 modal = true if modal.nil?
  41. 1 opts[:path] = add_path(modal ? :new_in_modal : :new)
  42. 1 modal ? modal_link_opts(opts) : opts
  43. end
  44. 1 view :add_url do
  45. card_url _render_add_path
  46. end
  47. 1 def add_path view
  48. 1 path_args = { mark: card.name }
  49. 1 process_voo_params(path_args) if voo.params
  50. 1 if view == :new
  51. path_args[:action] = :new
  52. else
  53. 1 path_args[:action] = :type
  54. 1 path_args[:view] = view
  55. end
  56. 1 path path_args
  57. end
  58. # don't cache because it depends on update permission for another card
  59. 1 view :configure_link, cache: :never, perms: ->(fmt) { fmt.can_configure? } do
  60. configure_link
  61. end
  62. 1 def can_configure?
  63. 1 Card.fetch(card, :type, :structure, new: {}).ok? :update
  64. end
  65. 1 view :configure_button, cache: :never, denial: :blank,
  66. 1 perms: ->(fmt) { fmt.can_configure? } do
  67. 1 configure_link "btn btn-secondary"
  68. end
  69. 1 def configure_link css_class=nil
  70. 1 return "" unless Card.fetch(card, :type, :structure, new: {}).ok? :update
  71. 1 voo.title ||= tr(:configure_card, cardname: safe_name.pluralize)
  72. 1 title = _render_title
  73. 1 link_to_card card, title, path: { view: :bridge, bridge: { tab: :rules_tab },
  74. set: Card::Name[safe_name, :type] },
  75. class: css_classes("configure-type-link ml-3", css_class)
  76. end
  77. 1 private
  78. 1 def process_voo_params path_args
  79. context = ((@parent&.card) || card).name
  80. Rack::Utils.parse_nested_query(voo.params).each do |key, value|
  81. value = value.to_name.absolute(context) if value
  82. key = key.to_name.absolute(context)
  83. path_args[key] = value
  84. end
  85. end
  86. end
  87. 1 include Basic
  88. 1 def cards_of_type_exist?
  89. !new_card? && Card.where(trash: false, type_id: id).exists?
  90. end
  91. 1 def create_ok?
  92. Card.new(type_id: id).ok? :create
  93. end
  94. 1 def was_cardtype?
  95. 3 type_id_before_act == Card::CardtypeID
  96. end
  97. 1 event :check_for_cards_of_type, after: :validate_delete do
  98. errors.add :cardtype, tr(:cards_exist, cardname: name) if cards_of_type_exist?
  99. end
  100. 1 event :check_for_cards_of_type_when_type_changed,
  101. :validate, changing: :type, when: :was_cardtype? do
  102. if cards_of_type_exist?
  103. errors.add :cardtype, tr(:error_cant_alter, name: name_before_act)
  104. end
  105. end
  106. 1 event :validate_cardtype_name, :validate, on: :save, changed: :name do
  107. 4 if %r{[<>/]}.match?(name)
  108. errors.add :name, tr(:error_invalid_character_in_cardtype, banned: "<, >, /")
  109. end
  110. end
  111. end;end;end;end;
  112. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/type/cardtype.rb ~~

card/tmpsets/set/mod010-standard/type/layout_type.rb

66.67% lines covered

12 relevant lines. 8 lines covered and 4 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "LayoutType" cards
  4. #
  5. # -*- encoding : utf-8 -*-
  6. 1 module LayoutType;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/type/layout_type.rb"; end
  9. 1 include_set Type::Html
  10. 1 event :update_layout_registry, :finalize, on: :update do
  11. Card::Layout.deregister_layout name
  12. Card::Layout.register_layout_with_nest name, format
  13. end
  14. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  15. 1 view :core do
  16. with_nest_mode :template do
  17. process_content ::CodeRay.scan(_render_raw, :html).div
  18. end
  19. end
  20. end
  21. end;end;end;end;
  22. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/type/layout_type.rb ~~

card/tmpsets/set/mod010-standard/type/notification_template.rb

60.87% lines covered

23 relevant lines. 14 lines covered and 9 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "NotificationTemplate" cards
  4. #
  5. 1 module NotificationTemplate;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/type/notification_template.rb"; end
  8. 1 card_reader :contextual_class
  9. 1 card_reader :disappear
  10. 1 card_reader :message
  11. 1 def deliver context
  12. success.flash alert_message(context)
  13. end
  14. 1 def alert_message context
  15. mcard = message.present? ? message_card : self
  16. format(:html).alert_message context, mcard
  17. end
  18. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  19. 1 def alert_message context, message_card
  20. mformat = subformat message_card
  21. alert card.alert_class, true, card.disappear? do
  22. mformat.contextual_content context, view: alert_view(mformat)
  23. end
  24. end
  25. 1 def alert_view format
  26. format.respond_to?(:notify) ? format.notify : :core
  27. end
  28. end
  29. 1 def disappear?
  30. disappear.present? ? disappear_card.checked? : true
  31. end
  32. 1 def alert_class
  33. contextual_class.present? ? contextual_class_card.item_name : :success
  34. end
  35. end;end;end;end;
  36. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/type/notification_template.rb ~~

card/tmpsets/set/mod010-standard/type/number.rb

53.33% lines covered

15 relevant lines. 8 lines covered and 7 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Number" cards
  4. #
  5. 1 module Number;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/type/number.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def input_type
  10. :text_field
  11. end
  12. end
  13. 1 event :validate_number, :validate, on: :save do
  14. errors.add :content, tr(:not_numeric, content: content) unless valid_number?(content)
  15. end
  16. 1 def valid_number? string
  17. return true if string.empty?
  18. valid = true
  19. begin
  20. Kernel.Float(string)
  21. rescue ArgumentError, TypeError
  22. valid = false
  23. end
  24. valid
  25. end
  26. end;end;end;end;
  27. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/type/number.rb ~~

card/tmpsets/set/mod010-standard/type/phrase.rb

85.71% lines covered

7 relevant lines. 6 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Phrase" cards
  4. #
  5. 1 module Phrase;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/type/phrase.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def input_type
  10. :text_field
  11. end
  12. end
  13. end;end;end;end;
  14. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/type/phrase.rb ~~

card/tmpsets/set/mod010-standard/type/session.rb

69.44% lines covered

36 relevant lines. 25 lines covered and 11 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Session" cards
  4. #
  5. 1 module Session;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/type/session.rb"; end
  8. 1 include_set Pointer
  9. 1 def virtual?
  10. 74 session_content.present?
  11. end
  12. 1 def history?
  13. false
  14. end
  15. 1 def followable?
  16. false
  17. end
  18. 1 def recaptcha_on?
  19. 24 false
  20. end
  21. 1 def session_key
  22. 91 "_card_#{key}"
  23. end
  24. 1 def session_content
  25. 91 Env.session[session_key]
  26. end
  27. 1 def session_content= val
  28. Env.session[session_key] = val
  29. end
  30. 1 def content
  31. 45 db_content || session_content
  32. end
  33. 1 event :store_in_session, :prepare_to_store, on: :save do
  34. self.session_content = db_content
  35. abort :success
  36. end
  37. 1 event :delete_in_session, :prepare_to_store, on: :delete do
  38. self.session_content = nil
  39. abort :success
  40. end
  41. 1 def ok_to_create
  42. true
  43. end
  44. 1 def ok_to_update
  45. true
  46. end
  47. 1 def add_to_trash args
  48. yield args.merge trash: true
  49. end
  50. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  51. 1 before :core do
  52. voo.items[:view] = :name
  53. end
  54. end
  55. end;end;end;end;
  56. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/type/session.rb ~~

card/tmpsets/set/mod010-standard/type/toggle.rb

54.17% lines covered

24 relevant lines. 13 lines covered and 11 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Toggle" cards
  4. #
  5. 1 module Toggle;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/type/toggle.rb"; end
  8. 1 def checked?
  9. content == "1"
  10. end
  11. 1 view :core do
  12. case card.content.to_i
  13. when 1 then tr(:yes)
  14. when 0 then tr(:no)
  15. else
  16. "?"
  17. end
  18. end
  19. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  20. 1 view :input do
  21. toggle
  22. end
  23. 1 view :labeled_editor do
  24. toggle + toggle_label
  25. end
  26. 1 def toggle
  27. check_box :content
  28. end
  29. 1 def toggle_label
  30. label :content, card.name.tag
  31. end
  32. 1 def one_line_content
  33. short_content
  34. end
  35. 1 def short_content
  36. render_core
  37. end
  38. end
  39. end;end;end;end;
  40. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/type/toggle.rb ~~

card/tmpsets/set/mod010-standard/type/uri.rb

75.0% lines covered

12 relevant lines. 9 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Uri" cards
  4. #
  5. 1 module Uri;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/standard/set/type/uri.rb"; end
  8. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  9. 1 view :core do
  10. link_to_resource _render_raw, render_title
  11. end
  12. 1 view :url_link do
  13. link_to_resource _render_raw
  14. end
  15. end
  16. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  17. 1 def input_type
  18. :text_field
  19. end
  20. end
  21. end;end;end;end;
  22. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/standard/set/type/uri.rb ~~

card/tmpsets/set/mod011-card-mod-email/abstract/email_field.rb

90.0% lines covered

20 relevant lines. 18 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (EmailField)
  4. #
  5. 1 module EmailField;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-email/set/abstract/email_field.rb"; end
  8. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  9. # turn off autodetection of uri's
  10. 1 def chunk_list
  11. :references
  12. end
  13. end
  14. # format :html do
  15. # def pointer_items args
  16. # card.item_names(context: :raw).map do |iname|
  17. # wrap_item iname, args
  18. # end
  19. # end
  20. # end#
  21. 2 module EmailTextFormat; module_parent.send :register_set_format, Card::Format::EmailTextFormat, self; extend Card::Set::AbstractFormat
  22. 1 def email_addresses context
  23. 2 context ||= self
  24. 2 card.item_names(context: context.name).map do |name|
  25. # FIXME: context is processed twice here because pointers absolutize
  26. # item_names by default while other types can return relative names.
  27. # That's poor default behavior and should be fixed!
  28. 2 name = name.to_name.absolute context
  29. 2 email_address?(name) ? name : email_address_from_card(name, context)
  30. end.flatten.compact.join(", ")
  31. end
  32. 1 def email_address? string
  33. 2 string =~ /.+\@.+\..+/
  34. end
  35. 1 def email_address_from_card name, context
  36. 2 card = Card.fetch name
  37. 2 card.account&.email || email_addresses_from_card_content(card, context)
  38. end
  39. 1 def email_addresses_from_card_content card, context
  40. subformat(card).contextual_content(context).split(/[,\n]/)
  41. end
  42. end
  43. end;end;end;end;
  44. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-email/set/abstract/email_field.rb ~~

card/tmpsets/set/mod011-card-mod-email/abstract/test_context.rb

84.21% lines covered

19 relevant lines. 16 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (TestContext)
  4. #
  5. 1 module TestContext;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-email/set/abstract/test_context.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :core do
  10. 2 return super() if voo.hide? :test_context
  11. card.with_context test_context_card do
  12. super()
  13. end
  14. end
  15. 1 def test_context_card
  16. card.left.fetch(:test_context)&.item_card
  17. end
  18. end
  19. 2 module EmailHtmlFormat; module_parent.send :register_set_format, Card::Format::EmailHtmlFormat, self; extend Card::Set::AbstractFormat
  20. 1 view :core do
  21. 2 voo.hide! :test_context
  22. 2 super()
  23. end
  24. end
  25. 2 module EmailTextFormat; module_parent.send :register_set_format, Card::Format::EmailTextFormat, self; extend Card::Set::AbstractFormat
  26. 1 view :core do
  27. 4 voo.hide! :test_context
  28. 4 super()
  29. end
  30. end
  31. end;end;end;end;
  32. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-email/set/abstract/test_context.rb ~~

card/tmpsets/set/mod011-card-mod-email/all/email_html.rb

77.78% lines covered

9 relevant lines. 7 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (EmailHtml)
  4. #
  5. 1 module EmailHtml;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-email/set/all/email_html.rb"; end
  8. 2 module EmailHtmlFormat; module_parent.send :register_set_format, Card::Format::EmailHtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :unknown do
  10. ""
  11. end
  12. 1 view :compact_missing do
  13. ""
  14. end
  15. end
  16. end;end;end;end;
  17. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-email/set/all/email_html.rb ~~

card/tmpsets/set/mod011-card-mod-email/all/email_text.rb

72.73% lines covered

11 relevant lines. 8 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (EmailText)
  4. #
  5. 1 module EmailText;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-email/set/all/email_text.rb"; end
  8. 2 module EmailTextFormat; module_parent.send :register_set_format, Card::Format::EmailTextFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :unknown do
  10. ""
  11. end
  12. 1 view :compact_missing do
  13. ""
  14. end
  15. 1 view :last_action, perms: :none, cache: :never do
  16. _render_last_action_verb
  17. end
  18. end
  19. end;end;end;end;
  20. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-email/set/all/email_text.rb ~~

card/tmpsets/set/mod011-card-mod-email/right/bcc.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Bcc" cards
  4. #
  5. 1 module Bcc;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-email/set/right/bcc.rb"; end
  8. 1 include_set Abstract::EmailField
  9. end;end;end;end;
  10. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-email/set/right/bcc.rb ~~

card/tmpsets/set/mod011-card-mod-email/right/cc.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Cc" cards
  4. #
  5. 1 module Cc;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-email/set/right/cc.rb"; end
  8. 1 include_set Abstract::EmailField
  9. end;end;end;end;
  10. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-email/set/right/cc.rb ~~

card/tmpsets/set/mod011-card-mod-email/right/from.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+From" cards
  4. #
  5. 1 module From;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-email/set/right/from.rb"; end
  8. 1 include_set Abstract::EmailField
  9. end;end;end;end;
  10. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-email/set/right/from.rb ~~

card/tmpsets/set/mod011-card-mod-email/right/html_message.rb

91.67% lines covered

12 relevant lines. 11 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+HtmlMessage" cards
  4. #
  5. 1 module HtmlMessage;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-email/set/right/html_message.rb"; end
  8. 1 include_set Abstract::TestContext
  9. 1 def clean_html?
  10. false
  11. end
  12. 2 module EmailHtmlFormat; module_parent.send :register_set_format, Card::Format::EmailHtmlFormat, self; extend Card::Set::AbstractFormat
  13. 1 def email_content context
  14. 2 content = contextual_content context
  15. 2 return unless content.present?
  16. 2 Card::Mailer.layout content
  17. end
  18. end
  19. end;end;end;end;
  20. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-email/set/right/html_message.rb ~~

card/tmpsets/set/mod011-card-mod-email/right/subject.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Subject" cards
  4. #
  5. 1 module Subject;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-email/set/right/subject.rb"; end
  8. 1 include_set Abstract::TestContext
  9. end;end;end;end;
  10. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-email/set/right/subject.rb ~~

card/tmpsets/set/mod011-card-mod-email/right/text_message.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+TextMessage" cards
  4. #
  5. 1 module TextMessage;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-email/set/right/text_message.rb"; end
  8. 1 include_set Abstract::TestContext
  9. end;end;end;end;
  10. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-email/set/right/text_message.rb ~~

card/tmpsets/set/mod011-card-mod-email/right/to.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+To" cards
  4. #
  5. 1 module To;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-email/set/right/to.rb"; end
  8. 1 include_set Abstract::EmailField
  9. end;end;end;end;
  10. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-email/set/right/to.rb ~~

card/tmpsets/set/mod011-card-mod-email/type/email_template.rb

61.4% lines covered

57 relevant lines. 35 lines covered and 22 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "EmailTemplate" cards
  4. #
  5. 1 module EmailTemplate;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-email/set/type/email_template.rb"; end
  8. 1 def clean_html?
  9. false
  10. end
  11. 1 def deliver context=nil, fields={}, opts={}
  12. mail = format.mail context, fields, opts
  13. mail.deliver
  14. rescue Net::SMTPError => exception
  15. errors.add :exception, exception.message
  16. end
  17. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  18. 1 def mail context=nil, fields={}, opts={}
  19. 2 config = card.email_config context, fields, opts
  20. 2 fmt = self # self is <Mail::Message> within the new_mail block
  21. 2 Card::Mailer.new_mail config do
  22. 2 fmt.message_body self, config
  23. 2 fmt.add_attachments self, config.delete(:attach)
  24. end
  25. end
  26. 1 def message_body mail, config
  27. 2 config[:html_message] &&= config[:html_message].call mail
  28. 2 method, args = body_method_and_args config[:html_message].present?,
  29. config[:text_message].present?
  30. 8 args = Array.wrap(args).map { |arg| config[arg] }
  31. 2 send method, mail, *args
  32. end
  33. 1 def body_method_and_args html, text
  34. 2 if html && text
  35. 2 [:text_and_html_message, %i[text_message html_message attach]]
  36. elsif html
  37. %i[html_body html_message]
  38. else
  39. %i[text_body text_message]
  40. end
  41. end
  42. 1 def text_and_html_message mail, text_message, html_message, attachment_list=nil
  43. 2 fmt = self
  44. 2 if attachment_list&.any?
  45. mail.multipart_mixed text_message, html_message
  46. else
  47. 4 mail.text_part { body text_message }
  48. 4 mail.html_part { fmt.html_body self, html_message }
  49. end
  50. end
  51. 1 def multipart_mixed mail, text_message, html_message
  52. mail.content_type "multipart/mixed"
  53. mail.part content_type: "multipart/alternative" do |copy|
  54. copy.part content_type: "text/plain" do |plain|
  55. plain.body = text_message
  56. end
  57. copy.part content_type: "text/html" do |html|
  58. html.body = html_message
  59. end
  60. end
  61. end
  62. 1 def html_body mail, message
  63. 2 mail.content_type "text/html; charset=UTF-8"
  64. 2 mail.body message
  65. end
  66. 1 def text_body mail, message
  67. mail.content_type "text/plain; charset=UTF-8"
  68. mail.text_part { body message }
  69. end
  70. 1 def add_attachments mail, list
  71. 2 return unless list.present?
  72. each_valid_attachment list do |file, index|
  73. mail.add_file filename: attachment_name(file, index),
  74. content: File.read(file.path)
  75. end
  76. end
  77. 1 def each_valid_attachment list
  78. list.each_with_index do |cardname, index|
  79. next unless (file = Card[cardname]&.try(:attachment))
  80. yield file, index
  81. end
  82. end
  83. 1 def attachment_name file, number
  84. "attachment-#{number + 1}.#{file.extension}"
  85. end
  86. end
  87. end;end;end;end;
  88. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-email/set/type/email_template.rb ~~

card/tmpsets/set/mod011-card-mod-email/type/email_template/email_config.rb

93.62% lines covered

47 relevant lines. 44 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Type; module EmailTemplate;
  3. # Set: All "EmailTemplate+EmailConfig" cards (EmailConfig)
  4. #
  5. 1 module EmailConfig;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-email/set/type/email_template/email_config.rb"; end
  8. EMAIL_FIELDS =
  9. 1 %i[to from cc bcc attach subject text_message html_message].freeze
  10. EMAIL_FIELD_METHODS =
  11. 1 { subject: :contextual_content,
  12. text_message: :contextual_content,
  13. attach: :extended_item_contents }.freeze
  14. # @param [Card] context the card in whose context all email fields will be interpreted
  15. # @param [Hash] fields override any templated field configurations with hash values
  16. # @param [Hash] opts options for rendering. unknown options become format options
  17. # @option opts [Card, String, Integer] :auth user identifier. render as this user
  18. 1 def email_config context, fields={}, opts={}
  19. 2 @active_email_context = context || self
  20. 2 auth = opts.delete :auth
  21. 2 config = EMAIL_FIELDS.each_with_object({}) do |field, conf|
  22. 16 conf[field] = fields[field] || email_field_from_card(field, auth, opts)
  23. end
  24. 2 safe_from_and_reply_to! config
  25. 20 config.select { |_k, v| v.present? }
  26. end
  27. 1 def email_field_from_card field, auth, format_opts
  28. 14 return unless (field_card = fetch(field))
  29. 8 auth ||= field_card.updater
  30. 8 special_email_field_method(field, field_card, auth, format_opts) ||
  31. standard_email_field(field, field_card, auth, format_opts)
  32. end
  33. 1 def special_email_field_method field, field_card, auth, format_opts
  34. 8 method = "email_#{field}_field"
  35. 8 return unless respond_to? method
  36. 2 send method, field_card, auth, format_opts
  37. end
  38. 1 def standard_email_field field, field_card, auth, format_opts
  39. 6 method = EMAIL_FIELD_METHODS[field] || :email_addresses
  40. 6 format_opts = format_opts.merge format: :email_text
  41. 6 Auth.as auth do
  42. 6 field_card.format(format_opts).send method, @active_email_context
  43. end
  44. end
  45. # html messages return procs because image attachments can't be properly rendered
  46. # without a mail object. (which isn't available at initial config time)
  47. 1 def email_html_message_field message_card, auth, format_opts
  48. 2 proc do |mail|
  49. 2 Auth.as auth do
  50. 2 format_opts = format_opts.merge format: :email_html, active_mail: mail
  51. 2 message_card.format(format_opts).email_content @active_email_context
  52. end
  53. end
  54. end
  55. # whenever a default "from" field is configured in Card::Mailer, emails are always
  56. # actually "from" that address
  57. 1 def safe_from_and_reply_to! config
  58. 2 conf_name, conf_email = configured_from_name_and_email config[:from]
  59. 2 actual_email = Card::Mailer.default[:from] || conf_email
  60. 2 config[:from] = email_from_field_value conf_name, conf_email, actual_email
  61. 2 config[:reply_to] ||= actual_email
  62. end
  63. 1 def email_from_field_value conf_name, conf_email, actual_email
  64. 2 conf_text = conf_name || conf_email
  65. 2 if conf_text != actual_email
  66. %("#{conf_text}" <#{actual_email}>)
  67. 2 elsif actual_email.present?
  68. 2 actual_email
  69. else
  70. Card[WagnBotID].account.email
  71. end
  72. end
  73. 1 def configured_from_name_and_email raw_string
  74. 2 if raw_string =~ /(.*)\<(.*)>/
  75. [Regexp.last_match(1).strip, Regexp.last_match(2)]
  76. else
  77. 2 [nil, raw_string]
  78. end
  79. end
  80. end;end;end;end;end;
  81. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-email/set/type/email_template/email_config.rb ~~

card/tmpsets/set/mod012-card-mod-account/abstract/account_field.rb

54.55% lines covered

11 relevant lines. 6 lines covered and 5 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (AccountField)
  4. #
  5. 1 module AccountField;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-account/set/abstract/account_field.rb"; end
  8. # allow account owner to update account field content
  9. 1 def ok_to_update
  10. return true if own_account? && !name_changed? && !type_id_changed?
  11. super
  12. end
  13. # force inherit permission on create
  14. # (cannot be done with rule, because sets are not addressable)
  15. 1 def permission_rule_id action
  16. if action == :create
  17. left_permission_rule_id action
  18. else
  19. super
  20. end
  21. end
  22. end;end;end;end;
  23. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-account/set/abstract/account_field.rb ~~

card/tmpsets/set/mod012-card-mod-account/abstract/accountable.rb

56.0% lines covered

25 relevant lines. 14 lines covered and 11 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (Accountable)
  4. #
  5. 1 module Accountable;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-account/set/abstract/accountable.rb"; end
  8. 1 def account
  9. fetch :account, new: {}
  10. end
  11. 1 def default_account_status
  12. "active"
  13. end
  14. 1 def current_account?
  15. id && Auth.current_id == id
  16. end
  17. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  18. 1 def default_bridge_tab
  19. card.current_account? ? :account_tab : super
  20. end
  21. 1 view :account_tab do
  22. bridge_pill_sections "Account" do
  23. [["Settings", account_details_items],
  24. ["Content", account_content_items]]
  25. end
  26. end
  27. 1 def show_account_tab?
  28. card.account.real?
  29. end
  30. 1 def account_formgroups
  31. Auth.as_bot do
  32. subformat(card.account)._render :content_formgroups, structure: true
  33. end
  34. end
  35. 1 def account_details_items
  36. [
  37. ["Email and Password", :account,
  38. { path: { slot: { hide: %i[help_link bridge_link] } } }],
  39. ["Roles", :roles,
  40. { path: { view: :content_with_edit_button } }],
  41. ["Notifications", :follow]
  42. ]
  43. end
  44. 1 def account_content_items
  45. [["Created", :created],
  46. ["Edited", :edited]]
  47. end
  48. end
  49. end;end;end;end;
  50. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-account/set/abstract/accountable.rb ~~

card/tmpsets/set/mod012-card-mod-account/all/account.rb

85.19% lines covered

54 relevant lines. 46 lines covered and 8 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Account)
  4. #
  5. 1 module Account;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-account/set/all/account.rb"; end
  8. 1 module ClassMethods
  9. 1 def default_accounted_type_id
  10. UserID
  11. end
  12. end
  13. 1 def account
  14. 80 fetch :account
  15. end
  16. 1 def parties
  17. 1322 @parties ||= (all_enabled_roles << id).flatten.reject(&:blank?)
  18. end
  19. 1 def among? ok_ids
  20. 1296 ok_ids.any? do |ok_id|
  21. 1296 ok_id == AnyoneID ||
  22. 1251 (ok_id == AnyoneWithRoleID && all_enabled_roles.size > 1) ||
  23. parties.member?(ok_id)
  24. end
  25. end
  26. 1 def own_account?
  27. # card is +*account card of signed_in user.
  28. name.part_names[0].key == Auth.as_card.key &&
  29. name.part_names[1].key == Card[:account].key
  30. end
  31. 1 def read_rules
  32. 134 @read_rules ||= fetch_read_rules
  33. end
  34. 1 def read_rules_hash
  35. 778 @read_rules_hash ||= read_rules.each_with_object({}) { |id, h| h[id] = true }
  36. end
  37. 1 def fetch_read_rules
  38. 71 return [] if id == WagnBotID # always_ok, so not needed
  39. 71 ([AnyoneID] + parties).each_with_object([]) do |party_id, rule_ids|
  40. 251 next unless (cache = Card::Rule.read_rule_cache[party_id])
  41. 71 rule_ids.concat cache
  42. end
  43. end
  44. 1 def clear_roles
  45. @parties = @all_roles = @all_active_roles = @read_rules = nil
  46. end
  47. 1 def with_clear_roles
  48. a, b, c, d = @parties, @all_roles, @all_active_roles, @read_rules
  49. yield
  50. ensure
  51. @parties, @all_roles, @all_active_roles, @read_rules = a, b, c, d
  52. end
  53. 1 def all_enabled_roles
  54. 165 @all_active_roles ||= (id == AnonymousID ? [] : enabled_role_ids)
  55. end
  56. 1 def all_roles
  57. @all_roles ||= (id == AnonymousID ? [] : fetch_roles)
  58. end
  59. 1 def enabled_role_ids
  60. 74 Auth.as_bot do
  61. # workaround for broken migrations
  62. 74 return fetch_roles unless Card::Codename.exists? :enabled_roles
  63. 74 enabled = enabled_roles_card
  64. 74 enabled.virtual? ? enabled.item_ids : fetch_roles
  65. end
  66. end
  67. 1 def enabled_roles_card
  68. 74 fetch :enabled_roles, eager_cache: true, new: { type_id: SessionID }
  69. end
  70. 1 def fetch_roles
  71. 74 [AnyoneSignedInID] + role_ids_from_roles_trait
  72. end
  73. 1 def role_ids_from_roles_trait
  74. 74 Auth.as_bot do
  75. 74 role_trait = fetch :roles
  76. 74 role_trait ? role_trait.item_ids : []
  77. end
  78. end
  79. 1 event :generate_token do
  80. Digest::SHA1.hexdigest "--#{Time.zone.now.to_f}--#{rand 10}--"
  81. end
  82. 1 event :set_stamper, :prepare_to_validate do
  83. 332 self.updater_id = Auth.current_id
  84. 332 self.creator_id = updater_id if new_card?
  85. end
  86. end;end;end;end;
  87. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-account/set/all/account.rb ~~

card/tmpsets/set/mod012-card-mod-account/right/account.rb

54.29% lines covered

35 relevant lines. 19 lines covered and 16 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Account" cards
  4. #
  5. # -*- encoding : utf-8 -*-
  6. 1 module Account;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-account/set/right/account.rb"; end
  9. 1 card_accessor :email
  10. 1 card_accessor :password
  11. 1 card_accessor :salt
  12. 1 card_accessor :status
  13. 1 card_accessor :api_key
  14. 1 require_field :email
  15. 1 def accounted
  16. left
  17. end
  18. 1 def accounted_id
  19. left_id
  20. end
  21. 1 def ok_to_read
  22. own_account? ? true : super
  23. end
  24. # allow account owner to update account field content
  25. 1 def ok_to_update
  26. return true if own_account? && !name_changed? && !type_id_changed?
  27. super
  28. end
  29. 1 def changes_visible? act
  30. act.actions_affecting(act.card).each do |action|
  31. return true if action.card.ok? :read
  32. end
  33. false
  34. end
  35. 1 def send_account_email email_template
  36. ecard = Card[email_template]
  37. unless ecard&.type_id == EmailTemplateID
  38. raise Card::Error, "invalid email template: #{email_template}"
  39. end
  40. ecard.deliver self, to: email
  41. end
  42. 1 def validate_api_key! api_key
  43. api_key_card.validate! api_key
  44. end
  45. 1 def method_missing method, *args
  46. super unless args.empty? && (matches = method.match(/^(?<status>.*)\?$/))
  47. status == matches[:status]
  48. end
  49. 1 def respond_to_missing? method, _include_private=false
  50. method.match?(/\?/) ? true : super
  51. end
  52. end;end;end;end;
  53. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-account/set/right/account.rb ~~

card/tmpsets/set/mod012-card-mod-account/right/account/events.rb

38.46% lines covered

52 relevant lines. 20 lines covered and 32 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Right; module Account;
  3. # Set: All "+Account+Events" cards (Events)
  4. #
  5. #### ON CREATE
  6. 1 module Events;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-account/set/right/account/events.rb"; end
  9. 1 event :set_default_salt, :prepare_to_validate, on: :create do
  10. add_subfield(:salt).generate
  11. end
  12. 1 event :set_default_status, :prepare_to_validate, on: :create do
  13. add_subfield :status, content: (accounted&.try(:default_account_status) || "active")
  14. end
  15. # ON UPDATE
  16. # reset password emails contain a link to update the +*account card
  17. # and trigger this event
  18. 1 event :reset_password, :prepare_to_validate, on: :update, trigger: :required do
  19. verifying_token :reset_password_success, :reset_password_failure
  20. end
  21. 1 event :verify_and_activate, :prepare_to_validate, on: :update, trigger: :required do
  22. activatable do
  23. verifying_token :verify_and_activate_success, :verify_and_activate_failure
  24. add_subcard(accounted)&.try :activate_accounted
  25. end
  26. end
  27. 1 event :password_redirect, :finalize, on: :update, when: :password_redirect? do
  28. success << { id: name, view: "edit" }
  29. end
  30. # INTEGRATION
  31. 1 %i[password_reset_email verification_email welcome_email].each do |email|
  32. 3 event "send_#{email}".to_sym, :integrate, trigger: :required do
  33. send_account_email email
  34. end
  35. end
  36. ## EVENT HELPERS
  37. 1 def activatable
  38. abort :failure, "no field manipulation mid-activation" if subcards.present?
  39. # above is necessary because activation uses super user (Decko Bot),
  40. # so allowing subcards would be unsafe
  41. yield
  42. end
  43. # note: this only works in the context of an action.
  44. # if run independently, it will not activate an account
  45. 1 event :activate_account do
  46. add_subfield :status, content: "active"
  47. trigger_event! :send_welcome_email
  48. end
  49. 1 def verifying_token success, failure
  50. requiring_token do |token|
  51. result = Auth::Token.decode token
  52. if result.is_a?(String)
  53. aborting { send failure, result }
  54. else
  55. send success
  56. end
  57. end
  58. end
  59. 1 def requiring_token
  60. if !(token = Env.params[:token])
  61. aborting { errors.add :token, "is required" }
  62. else
  63. yield token
  64. end
  65. end
  66. 1 def password_redirect?
  67. Auth.current_id == accounted_id && password.blank?
  68. end
  69. 1 def verify_and_activate_success
  70. Auth.signin accounted_id
  71. Auth.as_bot # use admin permissions for rest of action
  72. activate_account
  73. success << ""
  74. end
  75. 1 def verify_and_activate_failure error_message
  76. send_verification_email
  77. errors.add "Sorry, #{error_message}. Please check your email for a new activation link."
  78. end
  79. 1 def reset_password_success
  80. Auth.signin accounted_id
  81. success << { id: name, view: :edit }
  82. abort :success
  83. end
  84. 1 def reset_password_failure error_message
  85. Auth.as_bot { send_password_reset_email }
  86. errors.add tr(:sorry_email_reset, error_msg: error_message)
  87. end
  88. end;end;end;end;end;
  89. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-account/set/right/account/events.rb ~~

card/tmpsets/set/mod012-card-mod-account/right/account/views.rb

60.0% lines covered

35 relevant lines. 21 lines covered and 14 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Right; module Account;
  3. # Set: All "+Account+Views" cards (Views)
  4. #
  5. 1 module Views;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-account/set/right/account/views.rb"; end
  8. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  9. 1 view :verify_url, cache: :never do
  10. raise Error::PermissionDenied unless card.ok?(:create) || card.action
  11. token_url :verify_and_activate, anonymous: true
  12. end
  13. 1 view :reset_password_url do
  14. raise Error::PermissionDenied unless card.password_card.ok? :update
  15. token_url :reset_password
  16. end
  17. 1 view :token_expiry do
  18. "(#{token_expiry_sentence}"
  19. end
  20. 1 view :token_days do
  21. Card.config.token_expiry / 1.day
  22. end
  23. # DEPRECATED
  24. 1 view :verify_days, :token_days
  25. 1 view :reset_password_days, :token_days
  26. 1 def token_url trigger, extra_payload={}
  27. card_url path(action: :update,
  28. card: { trigger: trigger },
  29. token: new_token(extra_payload))
  30. end
  31. 1 def token_expiry_sentence
  32. "Link will expire in #{render_token_days} days"
  33. end
  34. 1 def new_token extra_payload
  35. Auth::Token.encode card.accounted_id, extra_payload
  36. end
  37. end
  38. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  39. 1 view :core do
  40. [account_field_nest(:email, "email"),
  41. account_field_nest(:password, "password")]
  42. end
  43. 1 def account_field_nest field, title
  44. field_nest field, title: title, view: :labeled
  45. # edit: :inline, hide: [:help_link, :bridge_link]
  46. end
  47. 1 before :content_formgroups do
  48. voo.edit_structure = [[:email, "email"], [:password, "password"]]
  49. end
  50. 1 view :token_expiry do
  51. "<p><em>#{token_expiry_sentence}</em></p>"
  52. end
  53. end
  54. 2 module EmailHtmlFormat; module_parent.send :register_set_format, Card::Format::EmailHtmlFormat, self; extend Card::Set::AbstractFormat
  55. 1 def mail context, fields
  56. super context, fields.reverse_merge(to: card.email)
  57. end
  58. end
  59. end;end;end;end;end;
  60. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-account/set/right/account/views.rb ~~

card/tmpsets/set/mod012-card-mod-account/right/api_key.rb

57.14% lines covered

14 relevant lines. 8 lines covered and 6 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+ApiKey" cards
  4. #
  5. 1 module ApiKey;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-account/set/right/api_key.rb"; end
  8. 1 include_set Abstract::AccountField
  9. # DURATIONS = "second|minute|hour|day|week|month|year".freeze
  10. 1 def history?
  11. false
  12. end
  13. 1 view :raw do
  14. tr :private_data
  15. end
  16. 1 def validate! api_key
  17. error =
  18. case
  19. when !real? then [:token_not_found, tr(:error_token_not_found)]
  20. # when expired? then [:token_expired, tr(:error_token_expired)]
  21. when content != api_key then [:incorrect_token, tr(:error_incorrect_token)]
  22. end
  23. errors.add(*error) if error
  24. error.nil?
  25. end
  26. # def expired?
  27. # !permanent? && updated_at <= term.ago
  28. # end
  29. #
  30. # def permanent?
  31. # term == "permanent"
  32. # end
  33. # def term
  34. # @term ||=
  35. # if expiration.present?
  36. # term_from_string expiration
  37. # else
  38. # Card.config.token_expiry
  39. # end
  40. # end
  41. # def term_from_string string
  42. # string.strip!
  43. # return "permanent" if string == "none"
  44. # re_match = /^(\d+)[\.\s]*(#{DURATIONS})s?$/.match(string)
  45. # number, unit = re_match.captures if re_match
  46. # raise Card::Open::Error, tr(:exception_bad_expiration, example: '2 days') unless unit
  47. # number.to_i.send unit
  48. # end
  49. end;end;end;end;
  50. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-account/set/right/api_key.rb ~~

card/tmpsets/set/mod012-card-mod-account/right/email.rb

40.74% lines covered

27 relevant lines. 11 lines covered and 16 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Email" cards
  4. #
  5. # -*- encoding : utf-8 -*-
  6. 1 module Email;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-account/set/right/email.rb"; end
  9. 1 include_set Abstract::AccountField
  10. 1 event :validate_email, :validate, on: :save do
  11. if content? && content !~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
  12. errors.add :content, tr(:error_invalid_address)
  13. end
  14. end
  15. 1 event :validate_unique_email, after: :validate_email, on: :save do
  16. if content.present?
  17. Auth.as_bot do
  18. cql = { right_id: EmailID, eq: content, return: :id }
  19. cql[:not] = { id: id } if id
  20. cql_comment = tr(:search_email_duplicate, content: content)
  21. if Card.search(cql, cql_comment).first
  22. errors.add :content, tr(:error_not_unique)
  23. end
  24. end
  25. end
  26. end
  27. 1 event :downcase_email, :prepare_to_validate, on: :save do
  28. return if !content || content == content.downcase
  29. self.content = content.downcase
  30. end
  31. 1 def email_required?
  32. !left.system?
  33. end
  34. 1 def ok_to_read
  35. if own_email? || Auth.always_ok?
  36. true
  37. else
  38. deny_because tr(:deny_email_restricted)
  39. end
  40. end
  41. 1 def own_email?
  42. name.part_names[0].key == Auth.as_card.key
  43. end
  44. end;end;end;end;
  45. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-account/set/right/email.rb ~~

card/tmpsets/set/mod012-card-mod-account/right/password.rb

51.72% lines covered

29 relevant lines. 15 lines covered and 14 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Password" cards
  4. #
  5. 1 module Password;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-account/set/right/password.rb"; end
  8. 1 include_set Abstract::AccountField
  9. 1 def history?
  10. false
  11. end
  12. 1 def ok_to_read
  13. own_account? ? true : super
  14. end
  15. 1 event :encrypt_password, :store,
  16. on: :save, changed: :content,
  17. when: proc { !Card::Env[:no_password_encryptions] } do
  18. # no_password_encryptions = hack for import - fix with api for ignoring events
  19. salt = left&.salt
  20. self.content = Auth.encrypt content, salt
  21. # errors.add :password, 'need a valid salt'
  22. # turns out we have a lot of existing account without a salt.
  23. # not sure when that broke??
  24. end
  25. 1 event :validate_password, :validate, on: :save do
  26. return if content.length > 3
  27. errors.add :password, tr(:password_length)
  28. end
  29. 1 event :validate_password_present, :prepare_to_validate, on: :update do
  30. abort :success if content.blank?
  31. end
  32. 1 view :raw do
  33. tr :encrypted
  34. end
  35. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  36. 1 view :core, wrap: :em do
  37. render_raw
  38. end
  39. 1 view :input do
  40. card.content = ""
  41. password_field :content, class: "d0-card-content", autocomplete: autocomplete?
  42. end
  43. 1 def autocomplete?
  44. return "on" if @parent && @parent.card.name == "*signin+*account" # HACK
  45. "off"
  46. end
  47. end
  48. end;end;end;end;
  49. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-account/set/right/password.rb ~~

card/tmpsets/set/mod012-card-mod-account/right/roles.rb

36.84% lines covered

19 relevant lines. 7 lines covered and 12 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Roles" cards
  4. #
  5. 1 module Roles;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-account/set/right/roles.rb"; end
  8. 1 event :validate_permission_to_assign_roles, :validate, on: :save do
  9. return unless (fr = forbidden_roles).present?
  10. errors.add :permission_denied,
  11. "You don't have permission to assign the role#{'s' if fr.size > 1} "\
  12. "#{fr.map(&:name).to_sentence}" # LOCALIZE
  13. end
  14. 1 def forbidden_roles
  15. # restore old roles for permission check
  16. with_old_role_permissions do |new_roles|
  17. new_roles.select do |card|
  18. !Card.fetch(card, "*members").ok? :update
  19. end
  20. end
  21. end
  22. 1 def with_old_role_permissions
  23. new_roles = item_cards
  24. new_content = content
  25. left.clear_roles
  26. Auth.update_always_cache Card::Auth.as_id, nil
  27. self.content = db_content_before_act
  28. yield new_roles
  29. ensure
  30. self.content = new_content
  31. end
  32. end;end;end;end;
  33. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-account/set/right/roles.rb ~~

card/tmpsets/set/mod012-card-mod-account/right/salt.rb

72.73% lines covered

11 relevant lines. 8 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Salt" cards
  4. #
  5. 1 module Salt;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-account/set/right/salt.rb"; end
  8. 1 include_set Abstract::AccountField
  9. 1 def generate
  10. self.content = Digest::SHA1.hexdigest "--#{Time.zone.now}--"
  11. end
  12. 1 def history?
  13. false
  14. end
  15. 1 view :raw do
  16. tr :private_data
  17. end
  18. end;end;end;end;
  19. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-account/set/right/salt.rb ~~

card/tmpsets/set/mod012-card-mod-account/right/status.rb

64.29% lines covered

14 relevant lines. 9 lines covered and 5 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Status" cards
  4. #
  5. 1 module Status;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-account/set/right/status.rb"; end
  8. 1 include_set Abstract::AccountField
  9. 1 include_set Abstract::Pointer
  10. 1 def input_type
  11. :radio
  12. end
  13. 1 def option_names
  14. %w[unapproved unverified active blocked system]
  15. end
  16. 1 def ok_to_update
  17. if own_account? && !Auth.always_ok?
  18. deny_because you_cant(tr(:deny_not_change_own_account))
  19. else
  20. super
  21. end
  22. end
  23. end;end;end;end;
  24. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-account/set/right/status.rb ~~

card/tmpsets/set/mod012-card-mod-account/self/signin.rb

34.45% lines covered

119 relevant lines. 41 lines covered and 78 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Signin"
  4. #
  5. # The Sign In card manages logging in and out of the site.
  6. #
  7. 1 module Signin;
  8. 1 extend Card::Set
  9. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-account/set/self/signin.rb"; end
  10. # /:signin (core view) gives the login ui
  11. # /:signin?view=edit gives the forgot password ui
  12. # /update/:signin is the login action
  13. # /delete/:signin is the logout action
  14. # authentication event
  15. 1 event :signin, :validate, on: :update do
  16. email = subfield :email
  17. email &&= email.content
  18. pword = subfield :password
  19. pword &&= pword.content
  20. authenticate_or_abort email, pword
  21. end
  22. # abort after successful signin (do not save card)
  23. 1 event :signin_success, after: :signin do
  24. abort :success
  25. end
  26. 1 event :signout, :validate, on: :delete do
  27. Env.reset_session
  28. Auth.signin AnonymousID
  29. abort :success
  30. end
  31. # triggered by clicking "Reset my Password", this sends out the verification password
  32. # and aborts (does not sign in)
  33. 1 event :send_reset_password_token, before: :signin, on: :update, trigger: :required do
  34. email = subfield(:email)&.content
  35. send_reset_password_email_or_fail email
  36. end
  37. 1 def ok_to_read
  38. true
  39. end
  40. 1 def recaptcha_on?
  41. false
  42. end
  43. 1 def i18n_signin key
  44. I18n.t key, scope: "mod.card-mod-account.set.self.signin"
  45. end
  46. 1 def authenticate_or_abort email, pword
  47. abort_unless email, :email_missing
  48. abort_unless pword, :password_missing
  49. authenticate_and_signin(email, pword) || failed_signin(email)
  50. end
  51. 1 def authenticate_and_signin email, pword
  52. return unless (account = Auth.authenticate email, pword)
  53. Auth.signin account.left_id
  54. end
  55. 1 def failed_signin email
  56. errors.add :signin, signin_error_message(account_for(email))
  57. abort :failure
  58. end
  59. 1 def abort_unless value, error_key
  60. abort :failure, i18n_signin(error_key) unless value
  61. end
  62. 1 def signin_error_message account
  63. case
  64. when account.nil? then i18n_signin(:error_unknown_email)
  65. when !account.active? then i18n_signin(:error_not_active)
  66. else i18n_signin(:error_wrong_password)
  67. end
  68. end
  69. 1 def error_on field, error_key
  70. errors.add field, i18n_signin(error_key)
  71. end
  72. 1 def account_for email
  73. Auth.find_account_by_email email
  74. end
  75. 1 def send_reset_password_email_or_fail email
  76. aborting do
  77. break errors.add :email, i18n_signin(:error_blank) if email.blank?
  78. if (account = Auth.find_account_by_email(email))&.active?
  79. Auth.as_bot { account.send_password_reset_email }
  80. elsif account
  81. errors.add :account, i18n_signin(:error_not_active)
  82. else
  83. errors.add :email, i18n_signin(:error_not_recognized)
  84. end
  85. end
  86. end
  87. 1 def send_reset_password_email_or_fail email
  88. aborting do
  89. break if blank_email? email
  90. if (account = account_for email)&.active?
  91. send_reset_password_email account
  92. else
  93. reset_password_fail account
  94. end
  95. end
  96. end
  97. 1 def blank_email? email
  98. return false if email.present?
  99. error_on :email, :error_blank
  100. end
  101. 1 def send_reset_password_email account
  102. Auth.as_bot { account.send_password_reset_email }
  103. end
  104. 1 def reset_password_fail account
  105. if account
  106. error_on :account, :error_not_active
  107. else
  108. error_on :email, :error_not_recognized
  109. end
  110. end
  111. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  112. 1 view :core, cache: :never do
  113. voo.edit_structure = [signin_field(:email), signin_field(:password)]
  114. with_nest_mode :edit do
  115. card_form :update, recaptcha: :off, success: signin_success do
  116. [
  117. _render_content_formgroups,
  118. _render_signin_buttons
  119. ]
  120. end
  121. end
  122. end
  123. 1 view :open do
  124. voo.show :help
  125. voo.hide :menu
  126. super()
  127. end
  128. # FIXME: need a generic solution for this
  129. 1 view :title do
  130. voo.title ||= I18n.t(:sign_in_title, scope: "mod.card-mod-account.set.self.signin")
  131. super()
  132. end
  133. 1 view :open_content do
  134. # annoying step designed to avoid table of contents. sigh
  135. _render_core
  136. end
  137. 1 view :one_line_content do
  138. ""
  139. end
  140. 1 view :reset_password_success do
  141. # 'Check your email for a link to reset your password'
  142. frame { I18n.t(:check_email, scope: "mod.card-mod-account.set.self.signin") }
  143. end
  144. 1 view :signin_buttons do
  145. button_formgroup do
  146. [signin_button, signup_link, reset_password_link]
  147. end
  148. end
  149. # FORGOT PASSWORD
  150. 1 view :edit do
  151. reset_password_voo
  152. Auth.as_bot { super() }
  153. end
  154. 1 def reset_password_voo
  155. voo.title ||= card.i18n_signin(:forgot_password)
  156. voo.edit_structure = [signin_field(:email)]
  157. voo.hide :help
  158. end
  159. 1 view :edit_buttons do
  160. text = I18n.t :reset_my_password, scope: "mod.card-mod-account.set.self.signin"
  161. button_tag text, situation: "primary", class: "_close-modal-on-success"
  162. end
  163. 1 def signin_success
  164. "REDIRECT: #{Env.interrupted_action || '*previous'}"
  165. end
  166. 1 def signin_button
  167. text = I18n.t :sign_in, scope: "mod.card-mod-account.set.self.signin"
  168. button_tag text, situation: "primary"
  169. end
  170. 1 def signup_link
  171. text = I18n.t :or_sign_up, scope: "mod.card-mod-account.set.self.signin"
  172. subformat(Card[:account_links]).render! :sign_up, title: text
  173. end
  174. 1 def reset_password_link
  175. text = I18n.t :reset_password, scope: "mod.card-mod-account.set.self.signin"
  176. link = link_to_view :edit, text, path: { slot: { hide: :bridge_link } }
  177. # FIXME: inline styling
  178. raw("<div style='float:right'>#{link}</div>")
  179. end
  180. 1 def edit_view_hidden
  181. hidden_tags card: { trigger: :send_reset_password_token }
  182. end
  183. 1 def edit_success
  184. { view: :reset_password_success }
  185. end
  186. 1 def signin_field name
  187. nest_name = "".to_name.trait(name)
  188. [nest_name, { title: name.to_s, view: "titled",
  189. nest_name: nest_name, skip_perms: true }]
  190. end
  191. end
  192. end;end;end;end;
  193. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-account/set/self/signin.rb ~~

card/tmpsets/set/mod012-card-mod-account/type/role.rb

60.0% lines covered

15 relevant lines. 9 lines covered and 6 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Role" cards
  4. #
  5. 1 module Role;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-account/set/type/role.rb"; end
  8. 1 def disabled?
  9. Auth.current&.fetch(:disabled_roles)&.item_ids&.include? id
  10. end
  11. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  12. 1 view :link_with_checkbox, cache: :never do
  13. role_checkbox
  14. end
  15. 1 def role_checkbox
  16. name = card.disabled? ? "add_item" : "drop_item"
  17. subformat(Auth.current.field(:disabled_roles, new: {})).card_form :update do
  18. [check_box_tag(name, card.id, !card.disabled?, class: "_edit-item"),
  19. render_link]
  20. end
  21. end
  22. 1 def related_by_content_items
  23. super.unshift ["members", :members]
  24. end
  25. end
  26. end;end;end;end;
  27. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-account/set/type/role.rb ~~

card/tmpsets/set/mod012-card-mod-account/type/signup.rb

50.0% lines covered

32 relevant lines. 16 lines covered and 16 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Signup" cards
  4. #
  5. 1 module Signup;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-account/set/type/signup.rb"; end
  8. 1 include_set Abstract::Accountable
  9. 1 require_field :account
  10. 1 def default_account_status
  11. can_approve? ? "unverified" : "unapproved"
  12. end
  13. 1 def can_approve?
  14. Card.new(type_id: Card.default_accounted_type_id).ok? :create
  15. end
  16. 1 def activate_accounted
  17. self.type_id = Card.default_accounted_type_id
  18. end
  19. 1 event :auto_approve_with_verification, :validate, on: :create, when: :can_approve? do
  20. request_verification
  21. end
  22. 1 event :approve_with_verification, :validate, on: :update, trigger: :required do
  23. approvable { request_verification }
  24. end
  25. 1 event :approve_without_verification, :validate, on: :update, trigger: :required do
  26. # TODO: if validated here, add trigger and activate in storage phase
  27. approvable do
  28. activate_accounted
  29. account_subfield.activate_account
  30. end
  31. end
  32. 1 event :act_as_current_for_integrate_stage, :integrate, on: :create do
  33. # needs justification!
  34. Auth.current_id = id
  35. end
  36. 1 def account_subfield
  37. subfield(:account) || add_subfield(:account)
  38. end
  39. 1 def request_verification
  40. acct = account_subfield
  41. acct.add_subfield :status, content: "unverified"
  42. acct.trigger_event! :send_verification_email
  43. end
  44. 1 def approvable
  45. if can_approve?
  46. yield
  47. else
  48. abort :failure, "illegal approval" # raise permission denied?
  49. end
  50. end
  51. end;end;end;end;
  52. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-account/set/type/signup.rb ~~

card/tmpsets/set/mod012-card-mod-account/type/signup/views.rb

41.82% lines covered

55 relevant lines. 23 lines covered and 32 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Type; module Signup;
  3. # Set: All "Signup+Views" cards (Views)
  4. #
  5. 1 module Views;
  6. 1 extend Card::Set
  7. 2 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-account/set/type/signup/views.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def invitation?
  10. Auth.signed_in? && card.can_approve?
  11. end
  12. 1 view :new do
  13. voo.title = invitation? ? tr(:invite) : tr(:sign_up)
  14. super()
  15. end
  16. 1 view :content_formgroups do
  17. [account_formgroups, (card.structure ? edit_slot : "")].join
  18. end
  19. 1 view :new_buttons do
  20. button_formgroup do
  21. [standard_create_button, invite_button].compact
  22. end
  23. end
  24. 1 def invite_button
  25. return unless invitation?
  26. button_tag "Send Invitation", situation: "primary"
  27. end
  28. 1 view :core, template: :haml do
  29. @lines = [signup_line] + account_lines
  30. @body = process_content _render_raw
  31. end
  32. 1 def signup_line
  33. ["<strong>#{safe_name}</strong>",
  34. ("was" if invited?),
  35. "signed up on #{format_date card.created_at}"].compact.join " "
  36. end
  37. 1 def invited?
  38. !self_signup?
  39. end
  40. 1 def self_signup?
  41. card.creator_id == AnonymousID
  42. end
  43. 1 def account_lines
  44. if card.account
  45. verification_lines
  46. else
  47. [tr(:missing_account)]
  48. end
  49. end
  50. 1 def verification_lines
  51. [verification_sent_line, verification_link_line].compact
  52. end
  53. 1 def verification_sent_line
  54. account = card.account
  55. return unless account.email_card.ok?(:read)
  56. "A verification email has been sent to #{account.email}"
  57. end
  58. 1 def verification_link_line
  59. links = verification_links
  60. return if links.empty?
  61. links.join " "
  62. end
  63. 1 def verification_links
  64. [approve_with_token_link, approve_without_token_link, deny_link].compact
  65. end
  66. 1 def approve_with_token_link
  67. action = card.account.status == "unverified" ? "Resend" : "Send"
  68. approval_link "#{action} verification email", :with
  69. end
  70. 1 def approve_without_token_link
  71. approval_link "Approve without verification", :without
  72. end
  73. 1 def approval_link text, with_or_without
  74. return unless card.can_approve?
  75. link_to_card card, text,
  76. path: { action: :update,
  77. card: { trigger: "approve_#{with_or_without}_verification" } }
  78. end
  79. 1 def deny_link
  80. return unless card.ok? :delete
  81. link_to_card card, "Deny and delete", path: { action: :delete }
  82. end
  83. end
  84. end;end;end;end;end;
  85. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-account/set/type/signup/views.rb ~~

card/tmpsets/set/mod012-card-mod-account/type/user.rb

50.0% lines covered

36 relevant lines. 18 lines covered and 18 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "User" cards
  4. #
  5. 1 module User;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-account/set/type/user.rb"; end
  8. 1 include Basic
  9. 1 include_set Abstract::Accountable
  10. 1 attr_accessor :email
  11. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  12. 1 view :setup, unknown: true, perms: ->(_fmt) { Auth.needs_setup? } do
  13. with_nest_mode :edit do
  14. voo.title = "Your deck is ready to go!" # LOCALIZE
  15. voo.show! :help
  16. voo.hide! :menu
  17. voo.help = haml :setup_help
  18. Auth.as_bot { setup_form }
  19. end
  20. end
  21. 1 def setup_form
  22. frame_and_form :create do
  23. [
  24. setup_hidden_fields,
  25. _render_name_formgroup,
  26. account_formgroups,
  27. setup_form_buttons
  28. ]
  29. end
  30. end
  31. 1 def setup_form_buttons
  32. button_formgroup { setup_button }
  33. end
  34. 1 def setup_button
  35. submit_button text: "Set up", disable_with: "Setting up"
  36. end
  37. 1 def setup_hidden_fields
  38. hidden_tags(
  39. setup: true,
  40. success: "REDIRECT: #{path mark: ''}",
  41. "card[type_id]" => Card.default_accounted_type_id
  42. )
  43. end
  44. end
  45. 1 def setup?
  46. Card::Env.params[:setup]
  47. end
  48. 1 event :setup_as_bot, before: :check_permissions, on: :create, when: :setup? do
  49. abort :failure unless Auth.needs_setup?
  50. Auth.as_bot
  51. # we need bot authority to set the initial administrator roles
  52. # this is granted and inspected here as a separate event for
  53. # flexibility and security when configuring initial setups
  54. end
  55. 1 event :setup_first_user, :prepare_to_store, on: :create, when: :setup? do
  56. add_subcard "signup alert email+*to", content: name
  57. add_subfield :roles, content: roles_for_first_user
  58. end
  59. 1 def roles_for_first_user
  60. %i[help_desk shark administrator].map(&:cardname)
  61. end
  62. 1 event :signin_after_setup, :integrate, on: :create, when: :setup? do
  63. Auth.signin id
  64. end
  65. end;end;end;end;
  66. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-account/set/type/user.rb ~~

card/tmpsets/set/mod012-card-mod-account/type_plus_right/user/email.rb

70.0% lines covered

10 relevant lines. 7 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class TypePlusRight; module User;
  3. # Set: All "+Email" cards on "User" cards
  4. #
  5. # supports legacy references to <User>+*email
  6. 1 module Email;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-account/set/type_plus_right/user/email.rb"; end
  9. # (standard representation is now <User>+*account+*email)
  10. 1 view :raw do
  11. card.content_email || card.account_email || ""
  12. end
  13. 1 def content_email
  14. content if real?
  15. end
  16. 1 def account_email
  17. left&.account&.email
  18. end
  19. end;end;end;end;end;
  20. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-account/set/type_plus_right/user/email.rb ~~

card/tmpsets/set/mod013-navbar/abstract/account_dropdown.rb

100.0% lines covered

16 relevant lines. 16 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (AccountDropdown)
  4. #
  5. 1 module AccountDropdown;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/navbar/set/abstract/account_dropdown.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def link_to_mycard
  10. 15 link_to_card Auth.current.name, nil,
  11. id: "my-card-link", class: "nav-link #{classy('my-card')}"
  12. end
  13. 1 def account_dropdown &render_role_item
  14. 15 split_button link_to_mycard, nil do
  15. [
  16. 15 link_to_card([Auth.current, :account_settings], "Account"),
  17. 15 (["Roles", role_items(&render_role_item)] if special_roles?)
  18. ]
  19. end
  20. end
  21. 1 def special_roles?
  22. 15 Auth.current_roles.size > 1
  23. end
  24. 1 def role_items
  25. 12 Auth.current_roles.map do |role_name|
  26. 28 yield role_name
  27. end
  28. end
  29. end
  30. end;end;end;end;
  31. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/navbar/set/abstract/account_dropdown.rb ~~

card/tmpsets/set/mod013-navbar/abstract/pointer/html_views.rb

100.0% lines covered

7 relevant lines. 7 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Abstract; module Pointer;
  3. # Set: Abstract (Pointer, HtmlViews)
  4. #
  5. 1 module HtmlViews;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/navbar/set/abstract/pointer/html_views.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :nav_item do
  10. 23 nav_dropdown
  11. end
  12. end
  13. end;end;end;end;end;
  14. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/navbar/set/abstract/pointer/html_views.rb ~~

card/tmpsets/set/mod013-navbar/all/navbar_links.rb

93.33% lines covered

30 relevant lines. 28 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (NavbarLinks)
  4. #
  5. 1 module NavbarLinks;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/navbar/set/all/navbar_links.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :navbar_links, perms: :none do
  10. 46 wrap_with :ul, class: "navbar-nav" do
  11. 46 navbar_items
  12. end
  13. end
  14. # Iterates over all nests and links and renders them as bootstrap navbar items.
  15. # Items that are pointer cards become dropdowns
  16. 1 def navbar_items view: :nav_item, link_class: "nav-link"
  17. 46 process_content nil, chunk_list: :references do |chunk|
  18. 184 case chunk
  19. when Card::Content::Chunk::Link
  20. 184 link = chunk.render_link view: view, explicit_link_opts: { class: link_class }
  21. 184 chunk.explicit_link? && view == :nav_item ? wrap_with_nav_item(link) : link
  22. when Card::Content::Chunk::Nest
  23. content_nest chunk.options.merge view: view
  24. else
  25. chunk.process_chunk
  26. end
  27. end
  28. end
  29. # overridden in Abstact::Pointer to render dropdown
  30. 1 view :nav_item do
  31. 23 wrap_with_nav_item link_view(class: "nav-link")
  32. end
  33. 1 def wrap_with_nav_item content
  34. 115 wrap_with(:li, content, class: "nav-item")
  35. end
  36. 1 view :nav_link_in_dropdown do
  37. 46 link_to_card card, render_title, class: "dropdown-item"
  38. end
  39. 1 def nav_dropdown
  40. 23 wrap_with(:li, class: "nav-item dropdown") do
  41. [
  42. 23 dropdown_toggle_link,
  43. dropdown_menu
  44. ]
  45. end
  46. end
  47. 1 def dropdown_toggle_link
  48. 23 link_to(render_title, href: "#", class: "nav-link dropdown-toggle",
  49. "data-toggle": "dropdown")
  50. end
  51. 1 def dropdown_menu
  52. 23 wrap_with :div, dropdown_menu_items, class: "dropdown-menu"
  53. end
  54. 1 def dropdown_menu_items
  55. 23 navbar_items view: :nav_link_in_dropdown, link_class: "dropdown-item"
  56. end
  57. end
  58. end;end;end;end;
  59. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/navbar/set/all/navbar_links.rb ~~

card/tmpsets/set/mod013-navbar/right/enabled_roles.rb

77.14% lines covered

35 relevant lines. 27 lines covered and 8 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+EnabledRoles" cards
  4. #
  5. 1 module EnabledRoles;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/navbar/set/right/enabled_roles.rb"; end
  8. 1 include_set Abstract::AccountDropdown
  9. 1 def ok_to_read
  10. true
  11. end
  12. 1 def ok_to_update
  13. left_id == Auth.current_id
  14. end
  15. 1 def ok_to_create
  16. left_id == Auth.current_id
  17. end
  18. 1 def ensure_roles
  19. 12 self.content = Auth.current_roles.to_pointer_content if content.blank?
  20. end
  21. 1 event :validate_role_enabling, :validate, on: :save do
  22. illegal_roles = item_names - Auth.current_roles
  23. return if illegal_roles.empty?
  24. errors.add :content, "illegal roles: #{illegal_roles.to_sentence}" # LOCALIZE
  25. end
  26. 1 event :clear_roles_cache, :prepare_to_store, before: :store_in_session do
  27. clear_roles
  28. Auth.update_always_cache Auth.as_id, nil
  29. end
  30. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  31. # permission change compared to super
  32. 1 view :edit_inline, perms: :none, unknown: true, cache: :never, wrap: :slot do
  33. 12 super()
  34. end
  35. 1 def input_type
  36. 12 :checkbox
  37. end
  38. 1 def edit_success
  39. 12 { reload: true }
  40. end
  41. 1 def hidden_form_tags _action, opts
  42. 12 "#{super} #{hidden_tags card: { type_id: SessionID }}"
  43. end
  44. 1 def checkbox_input
  45. 12 card.ensure_roles
  46. 12 wrap_with :div, class: "pointer-checkbox-list" do
  47. 12 account_dropdown &method(:role_item_checkbox)
  48. end
  49. end
  50. 1 def role_item_checkbox role_name
  51. 28 haml :role_checkbox, id: "pointer-checkbox-#{role_name.to_name.key}",
  52. checked: card.item_names.include?(role_name),
  53. option_name: role_name
  54. end
  55. end
  56. end;end;end;end;
  57. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/navbar/set/right/enabled_roles.rb ~~

card/tmpsets/set/mod013-navbar/self/account_links.rb

85.71% lines covered

49 relevant lines. 42 lines covered and 7 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "AccountLinks"
  4. #
  5. 1 module AccountLinks;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/navbar/set/self/account_links.rb"; end
  8. 1 include_set Abstract::AccountDropdown
  9. 1 def ok_to_read
  10. true
  11. end
  12. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  13. 1 view :core, cache: :never do
  14. status_class = Auth.signed_in? ? "logged-in" : "logged-out"
  15. wrap_with :div, id: "logging", class: status_class do
  16. navbar_items.join "\n"
  17. end
  18. end
  19. 1 def navbar_items
  20. # removed invite for now
  21. links =
  22. 23 %i[my_card sign_out sign_up sign_in].map do |link_view|
  23. 92 render(link_view)
  24. end.compact
  25. 23 links.map do |link|
  26. 92 wrap_with_nav_item link
  27. end
  28. end
  29. 1 def self.link_options opts={}
  30. 5 options = { denial: :blank, cache: :never }.merge opts
  31. 97 options[:perms] = ->(r) { yield r } if block_given?
  32. 5 options.clone
  33. end
  34. 1 view :sign_up, link_options(&:show_signup_link?) do
  35. 8 link_to_card :signup, account_link_text(:sign_up),
  36. class: nav_link_class("signup-link"),
  37. path: { action: :new, mark: :signup }
  38. end
  39. 24 view(:sign_in, link_options { !Auth.signed_in? }) do
  40. 8 link_to_card :signin, account_link_text(:sign_in),
  41. class: nav_link_class("signin-link")
  42. end
  43. 24 view(:sign_out, link_options { Auth.signed_in? }) do
  44. 15 link_to_card :signin, account_link_text(:sign_out),
  45. class: nav_link_class("signout-link"),
  46. path: { action: :delete }
  47. end
  48. 1 view :invite, link_options(&:show_invite_link?) do
  49. link_to_card :signup, account_link_text(:invite),
  50. class: nav_link_class("invite-link"),
  51. path: { action: :new, mark: :signup }
  52. end
  53. 24 view(:my_card, link_options { Auth.signed_in? }) do
  54. 15 can_disable_roles? ? interactive_roles_dropdown : simple_roles_dropdown
  55. end
  56. 1 def interactive_roles_dropdown
  57. 12 nest(enabled_roles_card,
  58. view: :edit_inline, hide: %i[edit_inline_buttons name_formgroup])
  59. end
  60. 1 def simple_roles_dropdown
  61. 3 account_dropdown(&method(:link_to_card))
  62. end
  63. 1 def enabled_roles_card
  64. 12 Auth.current.fetch :enabled_roles, new: { type_id: SessionID }
  65. end
  66. 1 def role_list
  67. Auth.current_roles.map(&method(:link_to_card))
  68. end
  69. 1 def can_disable_roles?
  70. 15 Auth.current_roles.size > 1 &&
  71. Card::Codename.exists?(:enabled_roles) # workaround for broken migrations
  72. end
  73. 1 def account_link_text purpose
  74. 31 voo.title ||
  75. I18n.t(purpose, scope: "mod.card-mod-account.set.self.account_links")
  76. end
  77. 1 def nav_link_class type
  78. 31 "nav-link #{classy(type)}"
  79. end
  80. 1 def show_signup_link?
  81. 23 !Auth.signed_in? && Card.new(type_id: SignupID).ok?(:create)
  82. end
  83. 1 def show_invite_link?
  84. Auth.signed_in? &&
  85. Card.new(type_id: Card.default_accounted_type_id).ok?(:create)
  86. end
  87. end
  88. end;end;end;end;
  89. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/navbar/set/self/account_links.rb ~~

card/tmpsets/set/mod013-navbar/self/dropdown_divider.rb

88.89% lines covered

9 relevant lines. 8 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "DropdownDivider"
  4. #
  5. 1 module DropdownDivider;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/navbar/set/self/dropdown_divider.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :nav_item do
  10. wrap_with :div, "", class: "dropdown-divider"
  11. end
  12. 1 view :nav_link_in_dropdown do
  13. 23 wrap_with :div, "", class: "dropdown-divider"
  14. end
  15. end
  16. end;end;end;end;
  17. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/navbar/set/self/dropdown_divider.rb ~~

card/tmpsets/set/mod013-navbar/self/navbox.rb

100.0% lines covered

18 relevant lines. 18 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Navbox"
  4. #
  5. 1 module Navbox;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/navbar/set/self/navbox.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :navbox, cache: :never do
  10. 23 select_tag "query[keyword]", "", class: "_navbox navbox form-control w-100",
  11. placeholder: navbar_placeholder
  12. end
  13. 1 view :navbar do
  14. # FIXME: not bootstrap class here.
  15. 23 class_up "navbox-form", "form-inline"
  16. 23 render_core
  17. end
  18. 1 view :core do
  19. 23 form_tag path(mark: :search), method: "get", role: "search",
  20. class: classy("navbox-form", "nodblclick") do
  21. 23 wrap_with :div, class: "form-group w-100" do
  22. 23 render_navbox
  23. end
  24. end
  25. end
  26. # def initial_options
  27. # return "" unless (keyword = params.dig :query, :keyword)
  28. # options_for_select [keyword]
  29. # end
  30. # TODO: the more natural placeholder would be the content of the navbox card, no?
  31. # Also, the forced division of "raw" and "core" should probably be replaced
  32. # with a single haml template (for core view)
  33. 1 def navbar_placeholder
  34. 23 @@placeholder ||= begin
  35. 1 holder_card = Card["#{Card[:navbox].name}+*placeholder"]
  36. 1 holder_card ? holder_card.content : "Search"
  37. end
  38. end
  39. end
  40. end;end;end;end;
  41. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/navbar/set/self/navbox.rb ~~

card/tmpsets/set/mod013-navbar/type/html.rb

63.64% lines covered

11 relevant lines. 7 lines covered and 4 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Html" cards
  4. #
  5. 1 module Html;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card/mod/navbar/set/type/html.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. # deprecated; here to support old "*main menu" html cards in existing decks
  10. 1 view :navbar_links, perms: :none do
  11. wrap_with :ul, class: "navbar-nav" do
  12. item_links.map do |link|
  13. wrap_with(:li, class: "nav-item") { link }
  14. end.join "\n"
  15. end
  16. end
  17. 1 def item_links _args={}
  18. raw(render_core).split(/[,\n]/)
  19. end
  20. end
  21. end;end;end;end;
  22. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/navbar/set/type/html.rb ~~

card/tmpsets/set/mod014-card-mod-edit/all/bridge.rb

73.53% lines covered

34 relevant lines. 25 lines covered and 9 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Bridge)
  4. #
  5. 1 module Bridge;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/bridge.rb"; end
  8. 1 BRIDGE_TABS = { "Account" => :account_tab,
  9. "Guide" => :guide_tab,
  10. "Engage" => :engage_tab,
  11. "History" => :history_tab,
  12. "Related" => :related_tab,
  13. "Rules" => :rules_tab }.freeze
  14. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  15. 1 wrapper :bridge do
  16. 1 class_up "modal-dialog", "no-gaps"
  17. 1 voo.hide! :modal_footer
  18. 1 wrap_with_modal size: :full, title: bridge_breadcrumbs do
  19. 1 haml :bridge
  20. end
  21. end
  22. 1 def bridge_tabs
  23. 1 wrap do
  24. 1 tabs(visible_bridge_tabs, bridge_tab, load: :lazy) { _render bridge_tab }
  25. end
  26. end
  27. 1 def bridge_tab
  28. 1 @bridge_tab ||= bridge_param :tab
  29. end
  30. 1 def bridge_param key
  31. 1 params.dig(:bridge, key)&.to_sym || try("default_bridge_#{key}")
  32. end
  33. 1 def bridge_breadcrumbs
  34. 1 <<-HTML.strip_heredoc
  35. <nav aria-label="breadcrumb">
  36. <ol class="breadcrumb _bridge-breadcrumb">
  37. <li class="breadcrumb-item">#{card.name}</li>
  38. <li class="breadcrumb-item active">Edit</li>
  39. </ol>
  40. </nav>
  41. HTML
  42. end
  43. 1 def bridge_link_opts opts={}
  44. opts[:"data-slot-selector"] = bridge_slot_selector
  45. opts[:remote] = true
  46. add_class opts, "slotter"
  47. opts.bury :path, :layout, :overlay
  48. opts[:path][:view] ||= :content
  49. opts
  50. end
  51. 1 def bridge_slot_selector
  52. ".bridge-main > .overlay-container > .card-slot._bottomlay-slot," \
  53. ".bridge-main > ._overlay-container-placeholder > .card-slot"
  54. end
  55. 1 def default_bridge_tab
  56. 1 show_guide_tab? ? :guide_tab : :engage_tab
  57. end
  58. 1 def breadcrumb_data title, html_class=nil
  59. html_class ||= title.underscore
  60. { "data-breadcrumb": title, "data-breadcrumb-class": html_class }
  61. end
  62. end
  63. end;end;end;end;
  64. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/bridge.rb ~~

card/tmpsets/set/mod014-card-mod-edit/all/bridge/bridge_pills.rb

38.71% lines covered

31 relevant lines. 12 lines covered and 19 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module Bridge;
  3. # Set: All cards (Bridge, BridgePills)
  4. #
  5. 1 module BridgePills;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/bridge/bridge_pills.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. BRIDGE_PILL_UL_CLASSES =
  10. 1 "nav nav-pills _auto-single-select bridge-pills flex-column".freeze
  11. 1 BRIDGE_PILL_LI_CLASSES = "nav-item".freeze
  12. 1 def bridge_pills items
  13. list_tag class: BRIDGE_PILL_UL_CLASSES, items: { class: BRIDGE_PILL_LI_CLASSES } do
  14. items
  15. end
  16. end
  17. 1 def bridge_pill_items data, breadcrumb
  18. data.map do |text, field, extra_opts|
  19. opts = bridge_pill_item_opts breadcrumb, extra_opts, text
  20. mark = opts.delete(:mark) == :absolute ? field : [card, field]
  21. link_to_card mark, text, opts
  22. end
  23. end
  24. 1 def bridge_pill_item_opts breadcrumb, extra_opts, text
  25. opts = bridge_link_opts.merge("data-toggle": "pill")
  26. opts.merge! breadcrumb_data(breadcrumb)
  27. if extra_opts
  28. classes = extra_opts.delete :class
  29. add_class opts, classes if classes
  30. opts.deep_merge! extra_opts
  31. end
  32. opts["data-cy"] = "#{text.to_name.key}-pill"
  33. add_class opts, "nav-link"
  34. opts
  35. end
  36. 1 def bridge_pill_sections tab_name
  37. wrap_with :ul, class: BRIDGE_PILL_UL_CLASSES do
  38. yield.map { |args| bridge_pill_section(tab_name, *args) }
  39. end
  40. end
  41. 1 def bridge_pill_section tab_name, title, items
  42. wrap_with(:h6, title, class: "ml-1 mt-3") +
  43. wrap_each_with(:li, class: BRIDGE_PILL_LI_CLASSES) do
  44. bridge_pill_items(items, tab_name)
  45. end.html_safe
  46. end
  47. end
  48. end;end;end;end;end;
  49. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/bridge/bridge_pills.rb ~~

card/tmpsets/set/mod014-card-mod-edit/all/bridge/follow_section.rb

47.62% lines covered

21 relevant lines. 10 lines covered and 11 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module Bridge;
  3. # Set: All cards (Bridge, FollowSection)
  4. #
  5. 1 module FollowSection;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/bridge/follow_section.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def follow_section
  10. return unless show_follow?
  11. wrap_with :div, class: "mb-3" do
  12. [follow_button_group, followers_bridge_link, follow_overview_button]
  13. end
  14. end
  15. 1 def follow_button_group
  16. wrap_with :div, class: "btn-group btn-group-sm follow-btn-group" do
  17. [follow_button, follow_advanced]
  18. end
  19. end
  20. 1 def follow_overview_button
  21. link_to_card [Auth.current, :follow], "all followed cards",
  22. bridge_link_opts(class: "btn btn-sm btn-secondary",
  23. "data-cy": "follow-overview")
  24. end
  25. 1 def follow_advanced
  26. opts = bridge_link_opts(class: "btn btn-sm btn-primary",
  27. path: { view: :overlay_rule },
  28. "data-cy": "follow-advanced")
  29. opts[:path].delete :layout
  30. link_to_card card.follow_rule_card(Auth.current.name, new: {}),
  31. icon_tag("more_horiz"), opts
  32. end
  33. 1 def followers_bridge_link
  34. cnt = card.followers_count
  35. link_to_card card.name.field(:followers), "#{cnt} follower#{'s' unless cnt == 1}",
  36. bridge_link_opts(class: "btn btn-sm ml-2 btn-secondary slotter",
  37. remote: true, "data-cy": "followers")
  38. end
  39. end
  40. end;end;end;end;end;
  41. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/bridge/follow_section.rb ~~

card/tmpsets/set/mod014-card-mod-edit/all/bridge/related_section.rb

56.25% lines covered

16 relevant lines. 9 lines covered and 7 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module Bridge;
  3. # Set: All cards (Bridge, RelatedSection)
  4. #
  5. 1 module RelatedSection;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/bridge/related_section.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. RELATED_ITEMS =
  10. {
  11. 1 "by name" => [["children", :children],
  12. ["mates", :mates]],
  13. # FIXME: optimize,
  14. "by content" => [["links out", :links_to],
  15. ["links in", :linked_to_by],
  16. ["nests", :nests],
  17. ["nested by", :nested_by],
  18. ["references out", :refers_to],
  19. ["references in", :referred_to_by]]
  20. # ["by edit", [["creator", :creator],
  21. # ["editors", :editors],
  22. # ["last edited", :last_edited]]]
  23. }.freeze
  24. 1 def related_by_name_items
  25. pills = []
  26. if card.name.junction?
  27. pills += card.name.ancestors.map { |a| [a, a, { mark: :absolute }] }
  28. end
  29. pills += RELATED_ITEMS["by name"]
  30. pills
  31. end
  32. 1 def related_by_content_items
  33. RELATED_ITEMS["by content"]
  34. end
  35. 1 def related_by_type_items
  36. [["#{card.type} cards", [card.type, :type, :by_name], mark: :absolute]]
  37. end
  38. end
  39. end;end;end;end;end;
  40. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/bridge/related_section.rb ~~

card/tmpsets/set/mod014-card-mod-edit/all/bridge/tab_views.rb

46.15% lines covered

26 relevant lines. 12 lines covered and 14 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module Bridge;
  3. # Set: All cards (Bridge, TabViews)
  4. #
  5. 1 module TabViews;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/bridge/tab_views.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :engage_tab, wrap: { div: { class: "m-3 mt-4 _engage-tab" } }, cache: :never do
  10. [render_follow_section, discussion_section].compact
  11. end
  12. 1 view :history_tab, wrap: :slot do
  13. class_up "d0-card-body", "history-slot"
  14. voo.hide :act_legend
  15. acts_bridge_layout card.history_acts
  16. end
  17. 1 view :related_tab do
  18. bridge_pill_sections "Related" do
  19. %w[name content type].map do |section_name|
  20. ["by #{section_name}", send("related_by_#{section_name}_items")]
  21. end
  22. end
  23. end
  24. 1 view :rules_tab, unknown: true do
  25. class_up "card-slot", "flex-column"
  26. wrap do
  27. nest current_set_card, view: :bridge_rules_tab
  28. end
  29. end
  30. 1 view :follow_section, wrap: :slot, cache: :never do
  31. follow_section
  32. end
  33. 1 view :guide_tab, unknown: true do
  34. render_guide
  35. end
  36. 1 def discussion_section
  37. return unless show_discussion?
  38. field_nest(:discussion, view: :titled, title: "Discussion", show: :comment_box,
  39. hide: [:menu])
  40. end
  41. end
  42. end;end;end;end;end;
  43. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/bridge/tab_views.rb ~~

card/tmpsets/set/mod014-card-mod-edit/all/bridge/tab_visibility.rb

78.13% lines covered

32 relevant lines. 25 lines covered and 7 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module Bridge;
  3. # Set: All cards (Bridge, TabVisibility)
  4. #
  5. 1 module TabVisibility;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/bridge/tab_visibility.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def visible_bridge_tabs
  10. 1 Bridge::BRIDGE_TABS.select do |_title, view|
  11. 6 send "show_#{view}?"
  12. end
  13. end
  14. 1 private
  15. 1 def show_engage_tab?
  16. 1 return unless card.real?
  17. 1 show_follow? || show_discussion?
  18. end
  19. 1 def show_account_tab?
  20. 1 false
  21. end
  22. 1 def show_history_tab?
  23. 1 card.real?
  24. end
  25. 1 def show_related_tab?
  26. 1 card.real?
  27. end
  28. 1 def show_rules_tab?
  29. 1 true
  30. end
  31. 1 def show_guide_tab?
  32. 2 guide.present?
  33. end
  34. 1 def show_discussion?
  35. d_card = discussion_card
  36. return unless d_card
  37. permission_task = d_card.new_card? ? :update : :read
  38. d_card.ok? permission_task
  39. end
  40. 1 def discussion_card?
  41. card.junction? && card.name.tag_name.key == :discussion.cardname.key
  42. end
  43. 1 def discussion_card
  44. return if card.new_card? || discussion_card?
  45. card.fetch :discussion, skip_modules: true, new: {}
  46. end
  47. end
  48. end;end;end;end;end;
  49. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/bridge/tab_visibility.rb ~~

card/tmpsets/set/mod014-card-mod-edit/all/edit_content.rb

39.29% lines covered

28 relevant lines. 11 lines covered and 17 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (EditContent)
  4. #
  5. 1 module EditContent;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/edit_content.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :edit_form, wrap: :slot do
  10. voo.show :edit_type_row
  11. with_nest_mode :edit do
  12. edit_form
  13. end
  14. end
  15. 1 def edit_form
  16. voo.hide :edit_type_row
  17. form_opts = edit_form_opts.reverse_merge success: edit_success
  18. card_form(:update, form_opts) do
  19. [
  20. edit_view_hidden,
  21. _render_edit_type_row(home_view: :edit_type_row),
  22. # home_view is necessary for cancel to work correctly.
  23. # it seems a little strange to have to think about home_view here,
  24. # but the issue is that something currently has to happen prior to the
  25. # render to get voo.slot_options to have the write home view in
  26. # the slot wrap. Id think this would probably best be handled as an
  27. # option to #wrap that triggers a new heir voo
  28. _render_content_formgroups,
  29. _render_edit_buttons
  30. ]
  31. end
  32. end
  33. 1 view :edit, perms: :update, unknown: true, cache: :never,
  34. wrap: { modal: { footer: "",
  35. size: :edit_modal_size,
  36. title: :render_title,
  37. menu: :edit_modal_menu } } do
  38. add_name_context
  39. with_nest_mode :edit do
  40. voo.show :help
  41. voo.hide :save_button
  42. wrap true do
  43. [
  44. frame_help,
  45. _render_edit_form
  46. ]
  47. end
  48. end
  49. end
  50. 1 def edit_modal_size
  51. :large
  52. end
  53. 1 def edit_modal_menu
  54. wrap_with_modal_menu do
  55. [close_modal_window, render_bridge_link]
  56. end
  57. end
  58. 1 def edit_form_opts
  59. # for override
  60. { "data-slot-selector": "modal-origin", "data-slot-error-selector": ".card-slot" }
  61. end
  62. end
  63. end;end;end;end;
  64. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/edit_content.rb ~~

card/tmpsets/set/mod014-card-mod-edit/all/edit_inline.rb

57.14% lines covered

28 relevant lines. 16 lines covered and 12 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (EditInline)
  4. #
  5. 1 module EditInline;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/edit_inline.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :edit_inline, perms: :update, unknown: true, cache: :never, wrap: :slot do
  10. 12 voo.hide :name_formgroup, :type_formgroup
  11. 12 with_nest_mode :edit do
  12. 12 card_form :update, success: edit_success do
  13. [
  14. 12 edit_view_hidden,
  15. _render_content_formgroups,
  16. _render_edit_inline_buttons
  17. ]
  18. end
  19. end
  20. end
  21. 1 view :edit_name_row do
  22. edit_row_fixed_width "Name", card.name, :name_form
  23. end
  24. 1 view :edit_inline_buttons do
  25. button_formgroup do
  26. wrap_with "div", class: "d-flex" do
  27. [standard_save_button, cancel_in_place_button, delete_button]
  28. end
  29. end
  30. end
  31. # TODO: better styling for this so that is reusable
  32. # At the moment it is used for the name and type field in the bridge
  33. # (with fixed 50px width for the title column) and
  34. # for password and email for accounts (with fixed 75px width for the title column)
  35. # The view is very similar to labeled but with fixed edit link on the right
  36. # and a fixed width for the labels so that the content column is aligned
  37. # There is also the problem that label and content are not vertically aligned
  38. 1 view :edit_row do
  39. edit_row_fixed_width render_title, render_core, :edit_inline, 75
  40. end
  41. 1 def edit_row_fixed_width title, content, edit_view, width=50
  42. class_up "card-slot", "d-flex"
  43. wrap do
  44. ["<label class='w-#{width}px'>#{title}</label>",
  45. content,
  46. edit_inline_link(edit_view, align: :right)]
  47. end
  48. end
  49. 1 def edit_inline_link view=:edit_inline, align: :left
  50. align = align == :left ? "ml-2" : "ml-auto"
  51. link_to_view view, menu_icon, class: "#{align} edit-link", "data-cy": "edit-link"
  52. end
  53. 1 def cancel_in_place_button args={}
  54. args.reverse_merge! class: "cancel-button btn-sm", href: path
  55. cancel_button args
  56. end
  57. end
  58. end;end;end;end;
  59. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/edit_inline.rb ~~

card/tmpsets/set/mod014-card-mod-edit/all/edit_name.rb

45.16% lines covered

31 relevant lines. 14 lines covered and 17 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (EditName)
  4. #
  5. 1 module EditName;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/edit_name.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. # note: depends on js with selector ".edit_name-view .card-form"
  10. 1 view :edit_name, perms: :update do
  11. frame { name_form }
  12. end
  13. # note: depends on js with selector ".name_form-view .card-form"
  14. 1 view :name_form, perms: :update, wrap: :slot, cache: :never do
  15. name_form :edit_name_row
  16. end
  17. 1 def name_form success_view=nil
  18. card_form({ action: :update, id: card.id },
  19. # "main-success" => "REDIRECT",
  20. "data-update-origin": "true",
  21. success: edit_name_success(success_view)) do
  22. [hidden_edit_name_fields,
  23. _render_name_formgroup,
  24. rename_confirmation_alert,
  25. edit_name_buttons]
  26. end
  27. end
  28. 1 def edit_name_success view=nil
  29. success = { id: "_self" }
  30. success[:view] = view if view
  31. success
  32. end
  33. 1 def hidden_edit_name_fields
  34. hidden_tags old_name: card.name, card: { update_referers: false }
  35. end
  36. 1 def edit_name_buttons
  37. button_formgroup do
  38. [rename_and_update_button, rename_button, standard_cancel_button]
  39. end
  40. end
  41. # LOCALIZE
  42. 1 def rename_and_update_button
  43. submit_button text: "Rename and Update", disable_with: "Renaming",
  44. class: "renamer-updater"
  45. end
  46. 1 def rename_button
  47. button_tag "Rename", data: { disable_with: "Renaming" }, class: "renamer"
  48. end
  49. # LOCALIZE
  50. 1 def rename_confirmation_alert
  51. msg = "<h5>Are you sure you want to rename <em>#{safe_name}</em>?</h5>"
  52. msg << %(<h6>This may change names referred to by other cards.</h6>)
  53. msg << %(<p>You may choose to <em>update or ignore</em> the referers.</p>)
  54. msg << hidden_field_tag(:referers, 1)
  55. alert("warning", false, false, class: "hidden-alert") { msg }
  56. end
  57. end
  58. end;end;end;end;
  59. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/edit_name.rb ~~

card/tmpsets/set/mod014-card-mod-edit/all/edit_type.rb

74.07% lines covered

54 relevant lines. 40 lines covered and 14 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (EditType)
  4. #
  5. 1 module EditType;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/edit_type.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :edit_type, cache: :never, perms: :update do
  10. frame do
  11. _render_edit_type_form
  12. end
  13. end
  14. 1 view :edit_type_form, cache: :never, perms: :update, wrap: :slot do
  15. card_form :update, success: edit_type_success do
  16. [type_formgroup, render_new_buttons]
  17. end
  18. end
  19. 1 def edit_type_success
  20. { view: :core }
  21. end
  22. 1 view :edit_type_row do
  23. return _render_bridge_type_formgroup if voo.visible?(:type_form) { false }
  24. edit_row_fixed_width "Type", link_to_card(card.type), :bridge_type_formgroup
  25. end
  26. 1 view :bridge_type_formgroup, unknown: true, wrap: :slot do
  27. type_formgroup href: path(mark: card.id,
  28. view: :edit_form,
  29. assign: true,
  30. slot: { show: :type_form }),
  31. class: "live-type-field slotter",
  32. 'data-remote': true,
  33. 'data-slot-selector': ".card-slot.edit_form-view"
  34. end
  35. 1 view :type_formgroup do
  36. type_formgroup
  37. end
  38. 1 def type_formgroup args={}
  39. add_class args, "type-field"
  40. wrap_type_formgroup do
  41. type_field args
  42. end
  43. end
  44. 1 def wrap_type_formgroup
  45. 7 formgroup "Type", input: "type", class: "type-formgroup", help: false do
  46. 7 output [yield, hidden_field_tag(:assign, true)]
  47. end
  48. end
  49. 1 def type_field args={}
  50. 7 typelist = Auth.createable_types
  51. 7 current_type = type_field_current_value args, typelist
  52. 7 action_view.select_tag "card[type]", type_field_options(current_type),
  53. args.merge("data-select2-id": "#{unique_id}-#{Time.now.to_i}")
  54. end
  55. 1 def type_field_options current_type
  56. 7 types = grouped_types(current_type)
  57. 7 if types.size == 1
  58. options_for_select types.flatten[1], current_type
  59. else
  60. 7 grouped_options_for_select types, current_type
  61. end
  62. end
  63. 1 def grouped_types current_type
  64. 70 groups = Hash.new { |h, k| h[k] = [] }
  65. 7 allowed = ::Set.new Auth.createable_types
  66. 7 allowed << current_type if current_type
  67. 7 visible_cardtype_groups.each_pair do |name, items|
  68. 63 if name == "Custom"
  69. 7 Auth.createable_types.each do |type|
  70. 301 groups["Custom"] << type unless ::Card::Set::Self::Cardtype::GROUP_MAP[type]
  71. end
  72. else
  73. 56 items.each do |i|
  74. 259 groups[name] << i if allowed.include?(i)
  75. end
  76. end
  77. end
  78. 7 groups
  79. end
  80. 1 def visible_cardtype_groups
  81. 7 ::Card::Set::Self::Cardtype::GROUP
  82. end
  83. 1 def type_field_current_value args, typelist
  84. 7 return if args.delete :no_current_type
  85. 7 if !card.new_card? && !typelist.include?(card.type_name)
  86. # current type should be an option on existing cards,
  87. # regardless of create perms
  88. typelist.push(card.type_name).sort!
  89. end
  90. 7 card.type_name_or_default
  91. end
  92. end
  93. end;end;end;end;
  94. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/edit_type.rb ~~

card/tmpsets/set/mod014-card-mod-edit/all/editing.rb

46.88% lines covered

32 relevant lines. 15 lines covered and 17 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Editing)
  4. #
  5. 1 module Editing;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/editing.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. ###---( TOP_LEVEL (used by menu) NEW / EDIT VIEWS )
  10. 1 view :bridge, perms: :update, unknown: true, cache: :never, wrap: :bridge do
  11. with_nest_mode :edit do
  12. add_name_context
  13. voo.show :help
  14. wrap true, breadcrumb_data("Editing", "edit") do
  15. bridge_parts
  16. end
  17. end
  18. end
  19. 1 view :cardboard, :bridge
  20. 1 def bridge_parts
  21. voo.show! :edit_type_row
  22. [
  23. frame_help,
  24. _render_edit_name_row(home_view: :edit_name_row),
  25. # home_view is necessary for cancel to work correctly.
  26. # it seems a little strange to have to think about home_view here,
  27. # but the issue is that something currently has to happen prior to the
  28. # render to get voo.slot_options to have the write home view in
  29. # the slot wrap. I think this would probably best be handled as an
  30. # option to #wrap that triggers a new heir voo
  31. _render_edit_form
  32. ]
  33. end
  34. 1 def edit_success
  35. # for override
  36. end
  37. 1 def edit_view_hidden
  38. # for override
  39. end
  40. 1 view :edit_buttons do
  41. button_formgroup do
  42. wrap_with "div", class: "d-flex" do
  43. [standard_submit_button, edit_cancel_button, delete_button]
  44. end
  45. end
  46. end
  47. # TODO: add undo functionality
  48. 1 view :just_deleted, unknown: true do
  49. wrap { "#{render_title} deleted" }
  50. end
  51. 1 view :edit_rules, cache: :never, unknown: true do
  52. nest current_set_card, view: :bridge_rules_tab
  53. end
  54. 1 view :edit_structure, cache: :never do
  55. return unless card.structure
  56. nest card.structure_rule_card, view: :edit
  57. # FIXME: this stuff:
  58. # slot: {
  59. # cancel_slot_selector: ".card-slot.related-view",
  60. # cancel_path: card.format.path(view: :edit), hide: :edit_toolbar,
  61. # hidden: { success: { view: :open, "slot[subframe]" => true } }
  62. # }
  63. # }
  64. end
  65. 1 view :edit_nests, cache: :never do
  66. frame do
  67. with_nest_mode :edit do
  68. multi_card_edit
  69. end
  70. end
  71. end
  72. # FIXME: - view can recurse. temporarily turned off
  73. #
  74. # view :edit_nest_rules, cache: :never do
  75. # return ""#
  76. # view = args[:rule_view] || :field_related_rules
  77. # frame do
  78. # # with_nest_mode :edit do
  79. # nested_fields.map do |name, _options|
  80. # nest Card.fetch(name.to_name.trait(:self)),
  81. # view: :titled, title: name, rule_view: view,
  82. # hide: :set_label, show: :rule_navbar
  83. # end
  84. # end
  85. # end
  86. end
  87. end;end;end;end;
  88. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/editing.rb ~~

card/tmpsets/set/mod014-card-mod-edit/all/editor.rb

83.33% lines covered

30 relevant lines. 25 lines covered and 5 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Editor)
  4. #
  5. 1 module Editor;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/editor.rb"; end
  8. 1 Self::InputOptions.add_to_basket :options, "text area"
  9. 1 Self::InputOptions.add_to_basket :options, "text field"
  10. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  11. 1 def input_type
  12. 14 voo.input_type.present? ? voo.input_type : input_type_from_rule
  13. end
  14. 1 def input_type_from_rule
  15. 14 card.rule(:input_type)&.gsub(/[\[\]]/, "")&.tr(" ", "_")
  16. end
  17. 1 def input_method input_type
  18. 27 "#{input_type}_input"
  19. end
  20. # core view of card is input
  21. 1 def input_defined_by_card
  22. 7 with_card input_type do |input_card|
  23. nest input_card, view: :core
  24. end
  25. end
  26. # move somewhere more accessible?
  27. 1 def with_card mark
  28. 7 return nil unless (card = Card[mark])
  29. yield card
  30. rescue Card::Error::CodenameNotFound
  31. nil
  32. end
  33. 1 view :input, unknown: true do
  34. 20 try(input_method(input_type)) ||
  35. input_defined_by_card ||
  36. send(input_method(default_input_type))
  37. end
  38. 1 def default_input_type
  39. 7 :rich_text
  40. end
  41. 1 def rich_text_input
  42. 7 send "#{Cardio.config.rich_text_editor || :text_area}_editor_input"
  43. end
  44. 1 def text_area_input
  45. text_area :content, rows: 5, class: "d0-card-content",
  46. "data-card-type-code" => card.type_code
  47. end
  48. 1 def text_field_input
  49. text_field :content, class: classy("d0-card-content")
  50. end
  51. end
  52. end;end;end;end;
  53. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/editor.rb ~~

card/tmpsets/set/mod014-card-mod-edit/all/form.rb

79.34% lines covered

121 relevant lines. 96 lines covered and 25 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Form)
  4. #
  5. 1 module Form;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/form.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. # FIELDSET VIEWS
  10. # sometimes multiple card formgroups, sometimes just one
  11. 1 view :content_formgroups, cache: :never do
  12. 20 wrap_with :fieldset, edit_slot, class: classy("card-editor", "editor")
  13. end
  14. 1 view :name_formgroup do
  15. 3 formgroup "Name", input: "name", help: false do
  16. 3 raw name_field
  17. end
  18. end
  19. # single card content formgroup, labeled with "Content"
  20. 1 view :content_formgroup, unknown: true, cache: :never do
  21. 16 wrap_content_formgroup { content_field }
  22. end
  23. 1 view :edit_in_form, cache: :never, perms: :update, unknown: true do
  24. reset_form
  25. @in_multi_card_editor = true
  26. edit_slot
  27. end
  28. 1 view :conflict_tracker, cache: :never, unknown: true do
  29. 20 return unless card&.real?
  30. 1 card.last_action_id_before_edit = card.last_action_id
  31. 1 hidden_field :last_action_id_before_edit, class: "current_revision_id"
  32. end
  33. 1 def wrap_content_formgroup
  34. 8 formgroup("Content", input: :content, help: false,
  35. 8 class: classy("card-editor")) { yield }
  36. end
  37. 1 def button_formgroup
  38. 8 wrap_with :div, class: classy("form-group") do
  39. 8 wrap_with :div, yield
  40. end
  41. end
  42. 1 def name_field
  43. # value needed because otherwise gets wrong value if there are updates
  44. 3 text_field :name, value: card.name, autocomplete: "off"
  45. end
  46. 1 def content_field
  47. 20 with_nest_mode :normal do
  48. # by changing nest mode to normal, we ensure that editors (eg image
  49. # previews) can render core views.
  50. 20 output [_render_conflict_tracker, _render_input]
  51. end
  52. end
  53. # SAMPLE editor view for override
  54. # view :input do
  55. # text_area :content, rows: 5, class: "d0-card-content"
  56. # end
  57. 1 def edit_slot
  58. case
  59. 20 when inline_nests_editor? then _render_core
  60. when multi_card_editor? then multi_card_edit(true)
  61. when in_multi_card_editor? then editor_in_multi_card
  62. 20 else single_card_edit_field
  63. end
  64. end
  65. # test: render nests within a normal rendering of the card's content?
  66. # (as opposed to a standardized form)
  67. 1 def inline_nests_editor?
  68. 20 voo.input_type == :inline_nests
  69. end
  70. # test: are we opening a new multi-card form?
  71. 1 def multi_card_editor?
  72. 20 voo.structure || voo.edit_structure || # structure configured in voo
  73. card.structure || # structure in card rule
  74. edit_fields? # list of fields in card rule
  75. end
  76. # override and return true to optimize
  77. 1 def edit_fields?
  78. 20 edit_fields.present?
  79. end
  80. # test: are we already within a multi-card form?
  81. 1 def in_multi_card_editor?
  82. 20 @in_multi_card_editor.present?
  83. end
  84. 1 def single_card_edit_field
  85. 20 if voo.show?(:type_formgroup) || voo.show?(:name_formgroup)
  86. 8 _render_content_formgroup # use formgroup for consistency
  87. else
  88. 24 editor_wrap(:content) { content_field }
  89. end
  90. end
  91. 1 def editor_in_multi_card
  92. add_junction_class
  93. formgroup render_title,
  94. input: "content", help: true, class: classy("card-editor") do
  95. [content_field, (form.hidden_field(:type_id) if card.new_card?)]
  96. end
  97. end
  98. 1 def multi_card_edit fields_only=false
  99. field_configs = edit_field_configs fields_only
  100. return structure_link if field_configs.empty?
  101. field_configs.map do |name, options|
  102. nest name, options || {}
  103. end.join "\n"
  104. end
  105. 1 def structure_link
  106. # LOCALIZE
  107. structured = link_to_card card.structure_rule_card, "structured"
  108. "<label>Content</label>"\
  109. "<p><em>Uneditable; content is #{structured} without nests</em></p>"
  110. end
  111. # @param [Hash|Array] fields either an array with field names and/or field
  112. # cards or a hash with the fields as keys and a hash with nest options as
  113. # values
  114. 1 def process_edit_fields fields
  115. fields.map do |field, opts|
  116. field_nest field, opts
  117. end.join "\n"
  118. end
  119. ###
  120. # If you use subfield cards to render a form for a new card
  121. # then the subfield cards should be created on the new card not the existing
  122. # card that build the form
  123. 1 def form
  124. 42 @form ||= inherit(:form) || new_form
  125. end
  126. 1 def new_form
  127. 13 @form_root = true unless parent&.form_root
  128. 13 instantiate_builder(form_prefix, card, {})
  129. end
  130. 1 def reset_form
  131. @form = new_form
  132. end
  133. 1 def form_prefix
  134. case
  135. 14 when explicit_form_prefix then explicit_form_prefix # configured
  136. 14 when simple_form? then "card" # simple form
  137. when parent.card.name == card.name then parent.form_prefix # card nests self
  138. else edit_in_form_prefix
  139. end
  140. end
  141. 1 def simple_form?
  142. 14 form_root? || !form_root || !parent
  143. end
  144. 1 def edit_in_form_prefix
  145. "#{parent.form_prefix}[subcards][#{card.name.from form_context.card.name}]"
  146. end
  147. 1 def explicit_form_prefix
  148. 14 inherit :explicit_form_prefix
  149. end
  150. 1 def form_context
  151. form_root? || !form_root ? self : parent
  152. end
  153. 1 def form_root?
  154. 14 @form_root == true
  155. end
  156. 1 def form_root
  157. 15 return self if @form_root
  158. 15 parent ? parent.form_root : nil
  159. end
  160. 1 def card_form action, opts={}
  161. 20 @form_root = true
  162. 20 hidden = hidden_form_tags action, opts
  163. 20 form_for card, card_form_opts(action, opts) do |cform|
  164. 20 @form = cform
  165. 20 hidden + output(yield(cform))
  166. end
  167. end
  168. 1 def hidden_form_tags _action, opts
  169. 20 success = opts.delete :success
  170. 20 success_tags success
  171. end
  172. # @param action [Symbol] :create or :update
  173. # @param opts [Hash] html options
  174. # @option opts [Boolean] :redirect (false) if true form is no "slotter"
  175. 1 def card_form_opts action, opts={}
  176. 20 url, action = card_form_url_and_action action
  177. 20 html_opts = card_form_html_opts action, opts
  178. 20 form_opts = { url: url, html: html_opts }
  179. 20 form_opts[:remote] = true unless html_opts.delete(:redirect)
  180. 20 form_opts
  181. end
  182. 1 def card_form_html_opts action, opts={}
  183. 20 add_class opts, "card-form"
  184. 20 add_class opts, "slotter" unless opts[:redirect] || opts[:no_slotter]
  185. 20 add_class opts, "autosave" if action == :update
  186. 20 opts
  187. end
  188. 1 def card_form_url_and_action action
  189. 20 case action
  190. 20 when Symbol then [path(action: action), action]
  191. when Hash then [path(action), action[:action]]
  192. # for when non-action path args are required
  193. else
  194. raise Card::Error, "unsupported #card_form_url action: #{action}"
  195. end
  196. end
  197. 1 def editor_wrap type=nil
  198. 30 html_class = "editor"
  199. 30 html_class << " #{type}-editor" if type
  200. 30 wrap_with :div, class: html_class do
  201. 30 yield
  202. end
  203. end
  204. # FIELD VIEWS
  205. 1 def add_junction_class
  206. return unless card.name.junction?
  207. class_up "card-editor", "RIGHT-#{card.name.tag_name.safe_key}"
  208. end
  209. end
  210. end;end;end;end;
  211. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/form.rb ~~

card/tmpsets/set/mod014-card-mod-edit/all/form_buttons.rb

42.86% lines covered

42 relevant lines. 18 lines covered and 24 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (FormButtons)
  4. #
  5. 1 module FormButtons;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/form_buttons.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def standard_submit_button
  10. output [standard_save_button, standard_save_and_close_button]
  11. end
  12. 1 def standard_save_button opts={}
  13. return if voo&.hide?(:save_button)
  14. add_class opts, "submit-button btn-sm mr-3 _update-history-pills"
  15. opts[:text] ||= "Save"
  16. opts["data-cy"] = "save"
  17. submit_button opts
  18. end
  19. # @param opts [Hash]
  20. # @option close [:modal, :overlay]
  21. #
  22. 1 def standard_save_and_close_button opts={}
  23. close = opts.delete(:close) || :modal
  24. text = opts[:text] || "Save and Close"
  25. add_class opts, "submit-button btn-sm mr-3 _close-on-success"
  26. add_class opts, "_update-origin" unless opts[:no_origin_update]
  27. opts.reverse_merge! text: text, "data-cy": "submit-#{close}"
  28. submit_button opts
  29. end
  30. 1 def standard_cancel_button args={}
  31. 8 args.reverse_merge! class: "cancel-button ml-4", href: path, "data-cy": "cancel"
  32. 8 cancel_button args
  33. end
  34. 1 def modal_cancel_button
  35. modal_close_button "Cancel", situation: "secondary", class: "btn-sm cancel-button"
  36. end
  37. 1 def edit_cancel_button
  38. modal_cancel_button
  39. end
  40. 1 def new_cancel_button
  41. voo.show?(:cancel_button) && modal_cancel_button
  42. end
  43. 1 def delete_button opts={}
  44. link_to "Delete", delete_button_opts(opts)
  45. end
  46. 1 def delete_button_opts opts={}
  47. add_class opts, "slotter btn btn-outline-danger ml-auto btn-sm"
  48. opts["data-confirm"] = delete_confirm opts
  49. opts[:path] = { action: :delete }
  50. opts[:path][:success] = delete_success(opts) unless opts.delete(:no_success)
  51. opts[:remote] = true
  52. opts
  53. end
  54. 1 def delete_confirm opts
  55. opts.delete(:confirm) || "Are you sure you want to delete #{safe_name}?"
  56. end
  57. 1 def delete_success opts
  58. opts.delete(:success) || (main? ? "REDIRECT: *previous" : { view: :just_deleted })
  59. end
  60. end
  61. end;end;end;end;
  62. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/form_buttons.rb ~~

card/tmpsets/set/mod014-card-mod-edit/all/form_elements.rb

90.48% lines covered

42 relevant lines. 38 lines covered and 4 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (FormElements)
  4. #
  5. 1 module FormElements;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/form_elements.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def success_tags opts
  10. 20 return "" unless opts.present?
  11. 20 hidden_tags success: opts
  12. end
  13. # convert hash into a collection of hidden tags
  14. 1 def hidden_tags hash, base=nil
  15. 56 hash ||= {}
  16. 56 hash.inject("") do |result, (key, val)|
  17. 56 new_base = base ? "#{base}[#{key}]" : key
  18. 56 result + process_hidden_value(val, new_base)
  19. end
  20. end
  21. 1 def process_hidden_value val, base
  22. 56 case val
  23. when Hash
  24. 24 hidden_tags val, base
  25. when Array
  26. base += "[]"
  27. val.map do |v|
  28. hidden_field_tag base, v
  29. end.join
  30. else
  31. 32 hidden_field_tag base, val
  32. end
  33. end
  34. FIELD_HELPERS =
  35. %w[
  36. 1 hidden_field color_field date_field datetime_field datetime_local_field
  37. email_field month_field number_field password_field phone_field
  38. range_field search_field telephone_field text_area text_field time_field
  39. url_field week_field file_field label check_box radio_button
  40. ].freeze
  41. 1 FIELD_HELPERS.each do |method_name|
  42. 22 define_method(method_name) do |*args|
  43. form.send(method_name, *args)
  44. end
  45. end
  46. 1 def submit_button args={}
  47. 8 text = args.delete(:text) || "Submit"
  48. 8 args.reverse_merge! situation: "primary", data: {}
  49. 8 args[:data][:disable_with] ||= args.delete(:disable_with) || "Submitting"
  50. 8 button_tag text, args
  51. end
  52. # redirect to *previous if no :href is given
  53. 1 def cancel_button args={}
  54. 8 return unless voo.show? :cancel_button
  55. 8 text = args.delete(:text) || "Cancel"
  56. 8 add_class args, "btn btn-#{args.delete(:situation) || 'secondary'}"
  57. 8 add_class args, cancel_strategy(args[:redirect], args[:href])
  58. 8 args[:href] ||= path_to_previous
  59. 8 args["data-remote"] = true
  60. 8 link_to text, args
  61. end
  62. 1 def cancel_strategy redirect, href
  63. 8 redirect = href.blank? if redirect.nil?
  64. 8 redirect ? "redirecter" : "slotter"
  65. end
  66. 1 def path_to_previous
  67. 8 path mark: "*previous"
  68. end
  69. end
  70. end;end;end;end;
  71. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/form_elements.rb ~~

card/tmpsets/set/mod014-card-mod-edit/all/formgroup.rb

88.89% lines covered

27 relevant lines. 24 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Formgroup)
  4. #
  5. 1 module Formgroup;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/formgroup.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. # a formgroup has a label, an input and help text
  10. 1 def formgroup title, opts={}, &block
  11. 18 wrap_with :div, formgroup_div_args(opts[:class]) do
  12. 18 formgroup_body title, opts, &block
  13. end
  14. end
  15. 1 def formgroup_body title, opts, &block
  16. 18 label = formgroup_label opts[:input], title
  17. 18 editor_body = editor_wrap opts[:input], &block
  18. 18 help_text = formgroup_help_text opts[:help]
  19. 18 "#{label}<div>#{help_text} #{editor_body}</div>"
  20. end
  21. 1 def formgroup_label input, title
  22. 18 return if voo&.hide?(:title) || title.blank?
  23. 18 label_type = input || :content
  24. 18 form.label label_type, title
  25. end
  26. 1 def formgroup_div_args html_class
  27. 18 div_args = { class: ["form-group", html_class].compact.join(" ") }
  28. 18 div_args[:card_id] = card.id if card.real?
  29. 18 div_args[:card_name] = h card.name if card.name.present?
  30. 18 div_args
  31. end
  32. 1 def formgroup_help_text text=nil
  33. 18 return "" if text == false
  34. class_up "help-text", "help-block"
  35. voo.help = text if voo && text.to_s != "true"
  36. _render_help
  37. end
  38. end
  39. end;end;end;end;
  40. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/formgroup.rb ~~

card/tmpsets/set/mod014-card-mod-edit/all/new.rb

79.79% lines covered

94 relevant lines. 75 lines covered and 19 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (New)
  4. #
  5. 1 module New;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/new.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :new, perms: :create, unknown: true, cache: :never do
  10. 8 new_view_frame_and_form new_form_opts
  11. end
  12. 1 view :new_content_form, wrap: :slot, unknown: true, cache: :never do
  13. with_nest_mode :edit do
  14. create_form
  15. end
  16. end
  17. 1 view :new_in_modal, perms: :create, unknown: true, cache: :never,
  18. wrap: { modal: { footer: "", size: :edit_modal_size,
  19. title: :new_in_modal_title,
  20. menu: :new_modal_menu } } do
  21. _render_new_content_form
  22. end
  23. 1 def create_form
  24. form_opts = new_in_modal_form_opts.reverse_merge(success: new_in_modal_success)
  25. buttons = form_opts.delete(:buttons) || _render_new_buttons
  26. voo.title ||= new_view_title if new_name_prompt?
  27. voo.show :help
  28. card_form(:create, form_opts) do
  29. create_form_with_alert_guide buttons
  30. end
  31. end
  32. 1 def new_modal_size
  33. :large
  34. end
  35. 1 def new_modal_menu
  36. wrap_with_modal_menu do
  37. [close_modal_window, render_bridge_link]
  38. end
  39. end
  40. 1 def new_view_frame_and_form form_opts={}
  41. 8 buttons = form_opts.delete(:buttons) || _render_new_buttons
  42. 8 form_opts = form_opts.reverse_merge(success: new_success)
  43. 8 with_nest_mode :edit do
  44. 8 voo.title ||= new_view_title if new_name_prompt?
  45. 8 voo.show :help
  46. 8 frame_and_form :create, form_opts do
  47. 8 create_form_with_alert_guide buttons
  48. end
  49. end
  50. end
  51. 1 def create_form_with_alert_guide buttons
  52. 8 wrap_with :div, class: "d-flex justify-content-between" do
  53. 8 [(wrap_with(:div, class: "w-100") do
  54. [
  55. 8 new_view_hidden,
  56. new_view_name,
  57. new_view_type,
  58. _render_content_formgroups,
  59. buttons
  60. ]
  61. end),
  62. 8 (alert_guide if voo.show?(:guide))]
  63. end
  64. end
  65. 1 def new_view_hidden; end
  66. 1 def new_in_modal_form_opts
  67. { "data-slot-selector": "modal-origin", "data-slot-error-selector": ".card-slot",
  68. buttons: _render_new_in_modal_buttons }
  69. end
  70. 1 def new_form_opts
  71. 8 { "main-success" => "REDIRECT" }
  72. end
  73. 1 def new_view_title
  74. 3 output(
  75. "New",
  76. 3 (card.type_name unless card.type_id == Card.default_type_id)
  77. )
  78. end
  79. 1 def new_in_modal_title
  80. new_name_prompt? ? new_view_title : render_title
  81. end
  82. 1 def new_success
  83. 8 card.rule(:thanks) || "_self"
  84. end
  85. 1 def new_in_modal_success; end
  86. # NAME HANDLING
  87. 1 def new_view_name
  88. 8 if new_name_prompt?
  89. 3 new_name_formgroup
  90. 5 elsif !autoname?
  91. 5 hidden_field_tag "card[name]", card.name
  92. end
  93. end
  94. 1 def new_name_formgroup
  95. 3 output _render_name_formgroup,
  96. hidden_field_tag("name_prompt", true)
  97. end
  98. 1 def new_name_prompt?
  99. 16 voo.visible? :name_formgroup do
  100. 8 needs_name? || params[:name_prompt]
  101. end
  102. end
  103. 1 def autoname?
  104. 8 @autoname.nil? ? (@autoname = card.rule_card :autoname).present? : @autoname
  105. end
  106. 1 def needs_name?
  107. 8 card.name.blank? && !autoname?
  108. end
  109. # TYPE HANDLING
  110. 1 def new_view_type
  111. 8 if new_type_prompt?
  112. 7 _render_new_type_formgroup
  113. else
  114. 1 hidden_field_tag "card[type_id]", card.type_id
  115. end
  116. end
  117. 1 def new_type_prompt?
  118. 8 voo.visible? :new_type_formgroup do
  119. 8 !new_type_preset? && new_type_prompt_context? && new_type_permitted?
  120. end
  121. end
  122. 1 def new_type_preset?
  123. 8 params[:type] || voo.type
  124. end
  125. 1 def new_type_prompt_context?
  126. 7 main? || card.simple? || card.is_template?
  127. end
  128. 1 def new_type_permitted?
  129. 7 Card.new(type_id: card.type_id).ok? :create
  130. end
  131. 1 view :new_type_formgroup do
  132. 7 wrap_type_formgroup do
  133. 7 type_field class: "type-field live-type-field",
  134. href: path(view: :new),
  135. "data-remote" => true
  136. end
  137. end
  138. 1 view :new_buttons do
  139. 8 button_formgroup do
  140. 8 [standard_create_button, standard_cancel_button(cancel_button_new_args)]
  141. end
  142. end
  143. 1 view :new_in_modal_buttons do
  144. button_formgroup do
  145. wrap_with "div", class: "d-flex" do
  146. [standard_save_and_close_button(text: "Submit"), modal_cancel_button]
  147. end
  148. end
  149. end
  150. # path to redirect to after canceling a new form
  151. 1 def cancel_button_new_args
  152. href = case
  153. 16 when main? then path_to_previous
  154. when voo&.home_view then path(view: voo.home_view)
  155. else path(view: :unknown)
  156. end
  157. 8 { href: href }
  158. end
  159. 1 def standard_create_button
  160. 8 submit_button class: "submit-button create-submit-button"
  161. end
  162. end
  163. end;end;end;end;
  164. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/new.rb ~~

card/tmpsets/set/mod014-card-mod-edit/all/overlay_guide.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (OverlayGuide)
  4. #
  5. 1 module OverlayGuide;
  6. 1 extend Card::Set
  7. 2 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/overlay_guide.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :overlay_guide,
  10. cache: :never, unknown: true, template: :haml,
  11. wrap: { slot: { class: "_overlay d0-card-overlay card nodblclick" } } do
  12. # TODO: use a common template for this and the nest editor
  13. # (the common thing is that they both are an overlay of the bridge sidebar)
  14. # and maybe make it look more like the overlay on the left with the same close icon
  15. end
  16. end
  17. end;end;end;end;
  18. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/overlay_guide.rb ~~

card/tmpsets/set/mod014-card-mod-edit/all/template_nest.rb

33.33% lines covered

27 relevant lines. 9 lines covered and 18 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (TemplateNest)
  4. #
  5. 1 module TemplateNest;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/template_nest.rb"; end
  8. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  9. 1 view :template_nest, cache: :never, unknown: true do
  10. return "" unless voo.nest_name
  11. if voo.nest_name.to_name.field_only?
  12. with_nest_mode :normal do
  13. nest template_link_set_name, view: :template_link
  14. end
  15. else
  16. "{{#{voo.nest_syntax}}}"
  17. end
  18. end
  19. 1 def template_link_set_name
  20. name = voo.nest_name.to_name
  21. if name.absolute?
  22. name.trait_name :self
  23. else
  24. template_link_set_name_for_relative_name name
  25. end
  26. end
  27. 1 def template_link_set_name_for_relative_name name
  28. name = name.stripped.gsub(/^\+/, "")
  29. if (type = on_type_set)
  30. [type, name].to_name.trait_name :type_plus_right
  31. else
  32. name.to_name.trait_name :right
  33. end
  34. end
  35. 1 def on_type_set
  36. return unless
  37. (tmpl_set_name = parent.card.name.trunk_name) &&
  38. (tmpl_set_class_name = tmpl_set_name.tag_name) &&
  39. (tmpl_set_class_card = Card[tmpl_set_class_name]) &&
  40. (tmpl_set_class_card.codename == :type)
  41. tmpl_set_name.left_name
  42. end
  43. end
  44. end;end;end;end;
  45. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/all/template_nest.rb ~~

card/tmpsets/set/mod014-card-mod-edit/type/list.rb

66.67% lines covered

12 relevant lines. 8 lines covered and 4 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "List" cards
  4. #
  5. 1 module List;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/type/list.rb"; end
  8. 1 def input_type_content_options
  9. ["multiselect", "checkbox", "autocompleted list", "filtered list"]
  10. end
  11. 1 def show_content_options?
  12. true
  13. end
  14. 1 def show_input_type?
  15. true
  16. end
  17. 1 def field_settings
  18. %i[default help input_type content_options content_option_view]
  19. end
  20. end;end;end;end;
  21. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/type/list.rb ~~

card/tmpsets/set/mod014-card-mod-edit/type/plain_text.rb

72.73% lines covered

11 relevant lines. 8 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "PlainText" cards
  4. #
  5. 1 module PlainText;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/type/plain_text.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def input_type_content_options
  10. ["text area", "text field", "ace editor"]
  11. end
  12. end
  13. 1 def field_settings
  14. %i[default help input_type]
  15. end
  16. 1 def show_input_type?
  17. true
  18. end
  19. end;end;end;end;
  20. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/type/plain_text.rb ~~

card/tmpsets/set/mod014-card-mod-edit/type/pointer.rb

70.0% lines covered

10 relevant lines. 7 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Pointer" cards
  4. #
  5. 1 module Pointer;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-edit/set/type/pointer.rb"; end
  8. 1 def show_content_options?
  9. true
  10. end
  11. 1 def show_input_type?
  12. true
  13. end
  14. 1 def input_type_content_options
  15. %w[select radio autocomplete]
  16. end
  17. end;end;end;end;
  18. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-edit/set/type/pointer.rb ~~

card/tmpsets/set/mod015-card-mod-ace_editor/all/ace_editor.rb

77.78% lines covered

9 relevant lines. 7 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (AceEditor)
  4. #
  5. 1 module AceEditor;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-ace_editor/set/all/ace_editor.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def ace_editor_input
  10. text_area :content, rows: 5,
  11. class: "d0-card-content ace-editor-textarea",
  12. "data-ace-mode" => ace_mode
  13. end
  14. 1 def ace_mode
  15. :html
  16. end
  17. end
  18. end;end;end;end;
  19. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-ace_editor/set/all/ace_editor.rb ~~

card/tmpsets/set/mod015-card-mod-ace_editor/self/ace.rb

85.71% lines covered

7 relevant lines. 6 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Ace"
  4. #
  5. 1 module Ace;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-ace_editor/set/self/ace.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def raw_help_text
  10. "Configure [[https://ace.c9.io/|ace]], "\
  11. "Decko's default code editor, using these available "\
  12. "[[https://github.com/ajaxorg/ace/wiki/Configuring-Ace|options]]."
  13. end
  14. end
  15. end;end;end;end;
  16. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-ace_editor/set/self/ace.rb ~~

card/tmpsets/set/mod015-card-mod-ace_editor/self/script_ace.rb

100.0% lines covered

7 relevant lines. 7 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ScriptAce"
  4. #
  5. 1 module ScriptAce;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-ace_editor/set/self/script_ace.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 Self::ScriptLibraries.add_item :script_ace
  10. 1 Self::InputOptions.add_to_basket :options, "ace editor"
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-ace_editor/set/self/script_ace.rb ~~

card/tmpsets/set/mod015-card-mod-ace_editor/self/script_ace_config.rb

100.0% lines covered

7 relevant lines. 7 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ScriptAceConfig"
  4. #
  5. 1 module ScriptAceConfig;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-ace_editor/set/self/script_ace_config.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 Self::ScriptEditors.add_item :script_ace_config
  10. 1 All::Head::HtmlFormat.add_to_basket :mod_js_config, [:ace, "setAceConfig"]
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-ace_editor/set/self/script_ace_config.rb ~~

card/tmpsets/set/mod016-card-mod-bar_and_box/abstract/media.rb

64.29% lines covered

14 relevant lines. 9 lines covered and 5 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (Media)
  4. #
  5. 1 module Media;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bar_and_box/set/abstract/media.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def image_card
  10. @image_card ||= card.fetch(:image, new: {})
  11. end
  12. 1 def text_with_image opts={}
  13. class_up "media-left", "m-2"
  14. @image_card = Card.cardish(opts[:image]) if opts[:image]
  15. haml :media_snippet, normalized_text_with_image_opts(opts)
  16. end
  17. 1 private
  18. 1 def normalized_text_with_image_opts opts
  19. opts.reverse_merge! title: _render_title, text: "", size: voo.size, media_opts: {}
  20. end
  21. end
  22. end;end;end;end;
  23. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bar_and_box/set/abstract/media.rb ~~

card/tmpsets/set/mod016-card-mod-bar_and_box/all/bar.rb

81.67% lines covered

60 relevant lines. 49 lines covered and 11 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Bar)
  4. #
  5. 1 module Bar;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bar_and_box/set/all/bar.rb"; end
  8. 1 include_set Abstract::BsBadge
  9. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  10. 1 setting :bar_cols
  11. 1 setting :info_bar_cols
  12. 1 view :info_bar do
  13. render_bar show: :bar_middle
  14. end
  15. 1 before :bar do
  16. 32 class_up "bar", card.safe_set_keys
  17. 32 voo.hide! :bar_collapse_link
  18. 32 voo.hide :edit_link, :full_page_link, :bridge_link
  19. end
  20. 1 view :bar, unknown: :unknown_bar do
  21. 25 voo.hide :bar_middle
  22. 25 voo.hide :bar_bottom # needed for toggle
  23. 25 class_up_bar_sides(voo.show?(:bar_middle))
  24. # note: above cannot be in `before`, because before blocks run before viz processing
  25. 50 wrap { haml :bar }
  26. end
  27. 1 bar_cols 9, 3
  28. 1 info_bar_cols 5, 4, 3
  29. 1 view :unknown_bar, unknown: true do
  30. 2 voo.hide! :bar_middle, :bar_bottom, :bar_nav
  31. 4 wrap { haml :bar }
  32. end
  33. 1 before :expanded_bar do
  34. class_up "bar", card.safe_set_keys
  35. voo.hide! :bar_expand_link
  36. end
  37. 1 view :expanded_bar do
  38. class_up_bar_sides(false)
  39. wrap { haml :expanded_bar }
  40. end
  41. 1 def class_up_bar_sides middle
  42. 25 class_up_cols %w[bar-left bar-right], bar_cols
  43. 25 class_up_cols %w[bar-left bar-middle bar-right], info_bar_cols, "md" if middle
  44. end
  45. 1 def class_up_cols classes, cols, context=nil
  46. 25 classes.each_with_index do |cls, i|
  47. 50 class_up cls, ["col", context, cols[i]].compact.join("-")
  48. end
  49. end
  50. 1 view :bar_left do
  51. 25 bar_title
  52. end
  53. 1 def bar_title
  54. 25 return render_missing if card.unknown?
  55. 25 if voo.show?(:toggle)
  56. 25 link_to_view bar_title_toggle_view, render_title
  57. else
  58. render_title
  59. end
  60. end
  61. 1 def bar_title_toggle_view
  62. 25 voo.show?(:bar_bottom) ? :bar : :expanded_bar
  63. end
  64. 1 view :bar_right, unknown: :blank do
  65. 25 [(render(:short_content) unless voo.show?(:bar_middle)),
  66. render(:edit_button, optional: :hide)]
  67. end
  68. 1 view :bar_middle, unknown: :blank do
  69. render :short_content
  70. end
  71. 1 view :bar_bottom do
  72. render(nest_mode == :edit ? :edit : :core)
  73. end
  74. 1 view :bar_nav, unknown: true, wrap: { div: { class: "bar-nav" } } do
  75. 5 [render_bar_expand_link,
  76. render_bar_collapse_link,
  77. render_full_page_link,
  78. render_edit_link,
  79. render_bridge_link]
  80. end
  81. 1 view :bar_expand_link, unknown: true do
  82. 5 link_to_view :expanded_bar, icon_tag(:keyboard_arrow_down)
  83. end
  84. 1 view :bar_collapse_link, unknown: true do
  85. link_to_view :bar, icon_tag(:keyboard_arrow_up)
  86. end
  87. 1 view :edit_button do
  88. view = voo.edit == :inline ? :edit_inline : :edit
  89. link_to_view view, "Edit", class: "btn btn-sm btn-outline-primary mr-2"
  90. end
  91. end
  92. end;end;end;end;
  93. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bar_and_box/set/all/bar.rb ~~

card/tmpsets/set/mod016-card-mod-bar_and_box/all/box.rb

66.67% lines covered

12 relevant lines. 8 lines covered and 4 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Box)
  4. #
  5. 1 module Box;
  6. 1 extend Card::Set
  7. 2 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bar_and_box/set/all/box.rb"; end
  8. 1 view :box, template: :haml do
  9. voo.hide :menu
  10. end
  11. 1 view :box_top do
  12. render_title_link
  13. end
  14. 1 view :box_middle do
  15. _render_content
  16. end
  17. 1 view :box_bottom do
  18. [_render_creator_credit,
  19. _render_updated_by]
  20. end
  21. end;end;end;end;
  22. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bar_and_box/set/all/box.rb ~~

card/tmpsets/set/mod016-card-mod-bar_and_box/self/style_media.rb

100.0% lines covered

8 relevant lines. 8 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "StyleMedia"
  4. #
  5. 1 module StyleMedia;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bar_and_box/set/self/style_media.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 Self::StyleMods.add_item :style_media
  10. 1 def source_files
  11. 2 scss_files [:image_box]
  12. end
  13. end;end;end;end;
  14. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bar_and_box/set/self/style_media.rb ~~

card/tmpsets/set/mod016-card-mod-bar_and_box/type/image.rb

59.09% lines covered

22 relevant lines. 13 lines covered and 9 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Image" cards
  4. #
  5. 1 module Image;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bar_and_box/set/type/image.rb"; end
  8. IMAGE_BOX_SIZE_MAP = {
  9. 1 icon: :icon, small: :small, medium: :small, large: :medium, xlarge: :medium
  10. }.freeze
  11. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  12. 1 view :boxed, unknown: true do
  13. image_box { |size| render_core size: size }
  14. end
  15. 1 view :boxed_link, unknown: true do
  16. image_box { |size| link_to_card image_box_link_target, render_core(size: size) }
  17. end
  18. 1 def image_box
  19. voo.size ||= :medium
  20. wrap_with :div, title: image_box_title, class: "image-box #{voo.size}" do
  21. yield image_box_size
  22. end
  23. end
  24. ## METHODS FOR OVERRIDE
  25. 1 def image_box_size
  26. IMAGE_BOX_SIZE_MAP[voo.size.to_sym] || :medium
  27. end
  28. 1 def image_box_card_name
  29. card.name.junction? ? card.name.left : card.name
  30. end
  31. 1 def image_box_link_target
  32. image_box_card_name
  33. end
  34. 1 def image_box_title
  35. voo.title || image_box_card_name
  36. end
  37. end
  38. end;end;end;end;
  39. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bar_and_box/set/type/image.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/abstract/bootstrap_code_file.rb

94.29% lines covered

35 relevant lines. 33 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (BootstrapCodeFile)
  4. #
  5. 1 module BootstrapCodeFile;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/abstract/bootstrap_code_file.rb"; end
  8. 1 def self.included host_class
  9. 3 host_class.include_set Abstract::CodeFile
  10. 3 host_class.include OverrideCodeFile
  11. end
  12. 1 module OverrideCodeFile
  13. 1 def content
  14. 3 stylesheets.join "\n"
  15. end
  16. 1 def stylesheets
  17. 3 load_stylesheets unless @stylesheets
  18. 3 @stylesheets
  19. end
  20. 1 def add_bs_subdir sub_dir
  21. 2 Dir.glob("#{bootstrap_path}/#{sub_dir}/*.scss").each do |path|
  22. 45 load_from_path path
  23. end
  24. end
  25. 1 def mod_path
  26. 35 mod_root :bootstrap
  27. end
  28. 1 def bootstrap_path
  29. 34 "#{mod_path}/vendor/bootstrap/scss"
  30. end
  31. 1 def add_stylesheet filename, type: :scss
  32. load_from_path "#{mod_path}/lib/stylesheets/#{filename}.#{type}"
  33. end
  34. 1 def add_stylesheet_file path
  35. 1 load_from_path File.join(mod_path, path)
  36. end
  37. 1 def add_bs_stylesheet filename, type: :scss, subdir: nil
  38. 32 path = File.join(*[bootstrap_path, subdir, "_#{filename}.#{type}"].compact)
  39. 32 load_from_path path
  40. end
  41. 1 def load_from_path path
  42. 78 @stylesheets ||= []
  43. 78 Rails.logger.info "reading file: #{path}"
  44. 78 @stylesheets << File.read(path)
  45. end
  46. 1 def source_changed _since:
  47. false
  48. end
  49. 1 def existing_source_paths
  50. 3 []
  51. end
  52. end
  53. end;end;end;end;
  54. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/abstract/bootstrap_code_file.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/abstract/bootswatch_theme.rb

87.5% lines covered

56 relevant lines. 49 lines covered and 7 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (BootswatchTheme)
  4. #
  5. # Bootswatch themes are free themes for bootstrap available at https://bootswatch.com/.
  6. # For every bootswatch theme we have one card of card type "bootswatch skin".
  7. # They all have codenames following the pattern "#{theme_name}_skin".
  8. #
  9. # The original bootswatch theme is build from two files, `_variables.scss` and
  10. # `_bootswatch.scss`. The original bootstrap scss has to be put between those two.
  11. # `_variables.scss` overrides bootstrap variables, `_bootswatch.scss` overrides
  12. # bootstrap css (variables are defined with `!default` hence only the first appearance
  13. # has an effect, for css the last appearance counts)
  14. #
  15. # The content of a bootswatch theme card consists of four parts:
  16. # * pre_variables: hard-coded theme independent stuff
  17. # and bootstrap functions to make them available in the variables part
  18. # * variables: the content from `_variables.scss`,
  19. # * post_variables: the bootstrap css and libraries like select2 and
  20. # bootstrap-colorpicker that depend on the theme
  21. # * stylesheets: the content from `_bootswatch.scss` and custom styles
  22. #
  23. # For the original bootswatch themes all those parts are hard-coded and the content
  24. 1 module BootswatchTheme;
  25. 1 extend Card::Set
  26. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/abstract/bootswatch_theme.rb"; end
  27. # is taken from files.
  28. # The bootswatch theme content is taken directly from the files in the bootswatch
  29. # submodule. For the rest we use code file cards.
  30. # Cards of type "customized bootswatch skin" have the same structure but make the variables
  31. # and stylesheets part editable.
  32. #
  33. # Bootswatch theme cards are machine cards for the following reason.
  34. # Machine cards usually store all involved input cards of all nested levels in
  35. # there +*machine_input pointer. All those input cards
  36. # are processed separately and the result is joined to build the machine output.
  37. # That's a problem for this card when it's used as input.
  38. # A lot of the items depend on the variables scss and can't
  39. # be processed independently. Therefore we return only self as item card and join
  40. # the content of all the item cards in the content of the bootswatch theme card.
  41. # But then this card has to forward updates of its items to the machine cards it provides
  42. # input for.
  43. # To do that it is a machine itself and stores the generated machine output as its
  44. # content which will trigger the updates of other machines that use this card.
  45. 1 include_set Abstract::Machine
  46. 1 include_set Type::Scss
  47. 1 include_set Abstract::CodeFile
  48. 1 include_set Abstract::SkinBox
  49. 1 CONTENT_PARTS = %i[pre_variables variables post_variables stylesheets].freeze
  50. 1 PRE_VARIABLES_CARD_NAMES = %i[
  51. style_jquery_ui_smoothness
  52. bootstrap_functions
  53. ].freeze
  54. 1 POST_VARIABLES_CARD_NAMES = %i[
  55. bootstrap_core
  56. style_cards
  57. style_bootstrap_cards
  58. style_libraries
  59. style_mods
  60. ].freeze
  61. # @return [Array<Card::Name,String>]
  62. 1 def variables_card_names
  63. 1 []
  64. end
  65. # @return [Array<Card::Name,String>]
  66. 1 def stylesheets_card_names
  67. 1 []
  68. end
  69. # reject cards that don't contribute directly to the content like skin or pointer cards
  70. 1 def engine_input
  71. extended_input_cards.select { |ca| ca.type_id.in? [Card::ScssID, Card::CssID] }
  72. end
  73. # Don't create "+*machine output" file card
  74. # instead save the the output as the card's content is
  75. 1 def after_engine output
  76. Card::Auth.as_bot { update! db_content: output }
  77. end
  78. # needed to make the refresh_script_and_style method work with these cards
  79. 1 def source_files
  80. extended_input_cards.map do |i_card|
  81. i_card.try(:source_files)
  82. end.flatten.compact
  83. end
  84. # needed to make the refresh_script_and_style method work with these cards
  85. 1 def existing_source_paths
  86. 1 extended_input_cards.map do |i_card|
  87. 12 i_card.try(:existing_source_paths)
  88. end.flatten.compact
  89. end
  90. 1 def extended_input_cards
  91. 1 input_names.map do |n|
  92. 7 Card.fetch(n).extended_item_cards
  93. end.flatten.compact
  94. end
  95. 1 def content
  96. 1 CONTENT_PARTS.map do |n|
  97. 4 send "#{n}_content"
  98. end.join "\n"
  99. end
  100. 1 def pre_variables_content
  101. 1 load_content(*PRE_VARIABLES_CARD_NAMES)
  102. end
  103. 1 def variables_content
  104. load_content variables_card_names
  105. end
  106. 1 def post_variables_content
  107. 1 load_content(*POST_VARIABLES_CARD_NAMES)
  108. end
  109. 1 def stylesheets_content
  110. load_content stylesheets_card_names
  111. end
  112. 1 def input_names _args={}
  113. 1 (PRE_VARIABLES_CARD_NAMES + variables_card_names +
  114. POST_VARIABLES_CARD_NAMES + stylesheets_card_names).compact.map do |n|
  115. 7 Card.fetch_name(n)
  116. end.compact
  117. end
  118. 1 def item_names _args={}
  119. []
  120. end
  121. 1 def item_cards _args={}
  122. 4 [self]
  123. end
  124. 1 def load_content *names
  125. 9 cards = names.flatten.map { |n| Card.fetch(n)&.extended_item_cards }
  126. 2 cards.flatten.compact.map(&:content).join "\n"
  127. end
  128. 1 def scss_from_theme_file file
  129. 2 return "" unless (path = ::File.join(source_dir, "_#{file}.scss")) &&
  130. ::File.exist?(path)
  131. 2 ::File.read path
  132. end
  133. 1 def theme_name
  134. 1 /^(.+)_skin$/.match(codename)&.capture(0) ||
  135. /^(.+)[ _][sS]kin/.match(name)&.capture(0)&.downcase
  136. end
  137. 1 def source_dir
  138. 2 @source_dir ||= File.expand_path(
  139. "#{mod_root :bootstrap}/vendor/bootswatch/dist/#{theme_name}", __FILE__
  140. )
  141. end
  142. end;end;end;end;
  143. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/abstract/bootswatch_theme.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/abstract/bootswatch_theme/html_views.rb

60.0% lines covered

20 relevant lines. 12 lines covered and 8 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Abstract; module BootswatchTheme;
  3. # Set: Abstract (BootswatchTheme, HtmlViews)
  4. #
  5. 1 module HtmlViews;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/abstract/bootswatch_theme/html_views.rb"; end
  8. 1 include_set Abstract::Media
  9. 1 include_set Abstract::BsBadge
  10. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  11. 1 before :box do
  12. voo.show! :customize_button, :box_middle
  13. end
  14. 1 view :one_line_content do
  15. ""
  16. end
  17. 1 view :bar_left do
  18. class_up "card-title", "my-0 ml-2"
  19. class_up "media-left", "m-0"
  20. text_with_image size: :medium, title: "", text: _render_title,
  21. media_opts: { class: "align-items-center" }
  22. # field_nest(:image, view: :core) + wrap_with(:h4, render(:title))
  23. end
  24. 1 view :bar_right do
  25. customize_button text: "Customize"
  26. end
  27. 1 view :bar_bottom do
  28. wrap_with :code do
  29. render_core
  30. end
  31. end
  32. end
  33. end;end;end;end;end;
  34. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/abstract/bootswatch_theme/html_views.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/accordion.rb

28.57% lines covered

28 relevant lines. 8 lines covered and 20 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module Bootstrap;
  3. # Set: All cards (Bootstrap, Accordion)
  4. #
  5. 1 module Accordion;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/all/bootstrap/accordion.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def accordion_group list, collapse_id=nil, args={}
  10. collapse_id ||= card.name.safe_key
  11. accordions = ""
  12. index = 1
  13. case list
  14. when Array then accordions = list.join
  15. when String then accordions = list
  16. else
  17. list.each_pair do |title, content|
  18. accordions << accordion(title, content, "#{collapse_id}-#{index}")
  19. index += 1
  20. end
  21. end
  22. add_class args, "act-accordion-group w-100"
  23. wrap_with :div, class: args[:class], id: "accordion-#{collapse_id}",
  24. role: "tablist", "aria-multiselectable" => "true" do
  25. accordions
  26. end
  27. end
  28. 1 def accordion title, content, collapse_id=card.name.safe_key
  29. accordion_content =
  30. case content
  31. when Hash then accordion_group content, collapse_id
  32. when Array then content.present? && list_group(content)
  33. when String then content
  34. end
  35. <<-HTML.html_safe
  36. <div class="card">
  37. #{accordion_panel(title, accordion_content, collapse_id)}
  38. </div>
  39. HTML
  40. end
  41. 1 def accordion_panel title, body, collapse_id, _panel_heading_link=false
  42. if body
  43. <<-HTML
  44. <div class="card-header" role="tab" id="heading-#{collapse_id}">
  45. <h5 class="mb-0">
  46. <a data-toggle="collapse" data-parent="#accordion-#{collapse_id}" \
  47. href="##{collapse_id}" aria-expanded="true" \
  48. aria-controls="#{collapse_id}">
  49. #{title}
  50. </a>
  51. </h5>
  52. </div>
  53. <div id="#{collapse_id}" class="collapse" \
  54. role="tabpanel" aria-labelledby="heading-#{collapse_id}">
  55. <div class="card-body">
  56. #{body}
  57. </div>
  58. </div>
  59. HTML
  60. else
  61. <<-HTML
  62. <li class="list-group-item">
  63. <h4 class="card-header">#{title}</h4>
  64. </li>
  65. HTML
  66. end
  67. end
  68. end
  69. end;end;end;end;end;
  70. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/all/bootstrap/accordion.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/dropdown.rb

82.35% lines covered

34 relevant lines. 28 lines covered and 6 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module Bootstrap;
  3. # Set: All cards (Bootstrap, Dropdown)
  4. #
  5. 1 module Dropdown;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/all/bootstrap/dropdown.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def dropdown_button name, items_or_opts={}, opts={}
  10. items = block_given? ? yield : items_or_opts
  11. opts = items_or_opts if block_given?
  12. <<-HTML
  13. <div class="btn-group #{opts[:extra_css_class]}" role="group">
  14. <button class="btn btn-primary dropdown-toggle"
  15. data-toggle="dropdown" title="#{name}" aria-expanded="false"
  16. aria-haspopup="true">
  17. #{icon_tag opts[:icon] if opts[:icon]} #{name}
  18. <span class="caret"></span>
  19. </button>
  20. #{dropdown_list items, opts[:class], opts[:active]}
  21. </div>
  22. HTML
  23. end
  24. 1 def split_button main_button, active_item
  25. 15 wrap_with :div, class: "btn-group" do
  26. [
  27. 15 main_button,
  28. split_button_toggle,
  29. dropdown_list(yield, "dropdown-menu-right", active_item)
  30. ]
  31. end
  32. end
  33. 1 private
  34. # @param items
  35. # [String] plain html
  36. # [Array<String, Array>] list of item names
  37. # If an item is an array then the first element is used as header for a section.
  38. # The second item has to be an array with the item names for that section.
  39. # [Hash] key is used to identify active item, value is the item name.
  40. # @param active specifies which item to highlight as active. If items are given as array
  41. # it has to be the index of the active item. If items are given as hash it has to be
  42. # the key of that item.
  43. 1 def dropdown_list items, extra_css_class=nil, active=nil
  44. 15 wrap_with :ul, class: "dropdown-menu #{extra_css_class}", role: "menu" do
  45. list =
  46. 15 case items
  47. when Array
  48. 15 dropdown_array_list items, active
  49. when Hash
  50. dropdown_hash_list items, active
  51. else
  52. [items]
  53. end
  54. 15 list.flatten.compact.join "\n"
  55. end
  56. end
  57. 1 def dropdown_header text
  58. 12 content_tag(:h6, text, class: "dropdown-header")
  59. end
  60. 1 def dropdown_hash_list items, active=nil
  61. items.map { |key, item| dropdown_list_item item, key, active }
  62. end
  63. 1 def dropdown_array_list items, active=nil
  64. 85 items.map.with_index { |item, i| dropdown_list_item item, i, active }
  65. end
  66. 1 def dropdown_list_item item, active_test, active
  67. 58 return unless item
  68. 55 if item.is_a? Array
  69. 12 [dropdown_header(item.first), dropdown_array_list(item.second)]
  70. else
  71. 43 "<li class='dropdown-item#{' active' if active_test == active}'>#{item}</li>"
  72. end
  73. end
  74. 1 def split_button_toggle
  75. 15 wrap_with(:a,
  76. href: "#",
  77. class: "nav-link pl-0 dropdown-toggle dropdown-toggle-split",
  78. "data-toggle" => "dropdown",
  79. "aria-haspopup" => "true",
  80. "aria-expanded" => "false") do
  81. 15 '<span class="sr-only">Toggle Dropdown</span>'
  82. end
  83. end
  84. end
  85. end;end;end;end;end;
  86. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/all/bootstrap/dropdown.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/form.rb

100.0% lines covered

23 relevant lines. 23 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module Bootstrap;
  3. # Set: All cards (Bootstrap, Form)
  4. #
  5. 1 module Form;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/all/bootstrap/form.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def button_tag content_or_options=nil, options={}, &block
  10. 8 bootstrapify_button(block_given? ? content_or_options : options)
  11. 8 super(content_or_options, options, &block)
  12. end
  13. 1 def bootstrapify_button options
  14. 8 situation = options.delete(:situation) || "primary"
  15. 8 options[:class] = [options[:class], "btn", "btn-#{situation}"].compact * " "
  16. end
  17. 1 def type_field args={}
  18. 7 args[:class] ||= ""
  19. 7 args[:class] += " form-control"
  20. 7 super(args)
  21. end
  22. 1 def bootstrap_options options
  23. 24 options[:class] ||= ""
  24. 24 options[:class] += " form-control"
  25. 24 options
  26. end
  27. 1 FIELD_HELPERS = %w[hidden_field color_field date_field datetime_field
  28. datetime_local_field email_field month_field number_field
  29. password_field phone_field range_field search_field
  30. telephone_field text_area text_field time_field
  31. url_field week_field file_field].freeze
  32. 1 FIELD_HELPERS.each do |method_name|
  33. 19 define_method(method_name) do |name, options={}|
  34. 24 form.send(method_name, name, bootstrap_options(options))
  35. end
  36. end
  37. end
  38. end;end;end;end;end;
  39. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/all/bootstrap/form.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/helper.rb

40.0% lines covered

40 relevant lines. 16 lines covered and 24 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module Bootstrap;
  3. # Set: All cards (Bootstrap, Helper)
  4. #
  5. 1 module Helper;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/all/bootstrap/helper.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def button_link link_text, opts={}
  10. btn_type = opts.delete(:btn_type) || "primary"
  11. opts[:class] = [opts[:class], "btn btn-#{btn_type}"].compact.join " "
  12. smart_link_to link_text, opts
  13. end
  14. 1 def separator
  15. '<li role="separator" class="divider"></li>'
  16. end
  17. 1 def list_group content_or_options=nil, options={}
  18. options = content_or_options if block_given?
  19. content = block_given? ? yield : content_or_options
  20. content = Array(content).map(&:to_s)
  21. add_class options, "list-group"
  22. options[:items] ||= {}
  23. add_class options[:items], "list-group-item"
  24. list_tag content, options
  25. end
  26. 1 def list_tag content_or_options=nil, options={}
  27. options = content_or_options if block_given?
  28. content = block_given? ? yield : content_or_options
  29. content = Array(content)
  30. default_item_options = options.delete(:items) || {}
  31. tag = options[:ordered] ? :ol : :ul
  32. wrap_with tag, options do
  33. content.map do |item|
  34. i_content, i_opts = item
  35. i_opts ||= default_item_options
  36. wrap_with :li, i_content, i_opts
  37. end
  38. end
  39. end
  40. 1 def badge_tag content, options={}
  41. add_class options, "badge"
  42. wrap_with :span, content, options
  43. end
  44. 1 def popover_link text, title=nil, link_text=fa_icon("question-circle"), opts={}
  45. link_to link_text, popover_opts(text, title, opts)
  46. end
  47. 1 def popover_opts text, title, opts
  48. 6 add_class opts, "pl-1 text-muted-link"
  49. 6 opts.merge! path: "#", "data-toggle": "popover",
  50. "data-trigger": :focus, "data-content": text
  51. 6 opts["data-title"] = title if title
  52. 6 opts
  53. end
  54. end
  55. end;end;end;end;end;
  56. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/all/bootstrap/helper.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/icon.rb

91.18% lines covered

34 relevant lines. 31 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module Bootstrap;
  3. # Set: All cards (Bootstrap, Icon)
  4. #
  5. 1 module Icon;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/all/bootstrap/icon.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. # same for all:
  10. # :search,
  11. ICON_MAP = {
  12. 1 material: {
  13. plus: :add,
  14. pencil: :edit,
  15. trash: :delete,
  16. wrench: :build,
  17. new_window: :open_in_new,
  18. history: :history,
  19. triangle_left: :expand_less,
  20. triangle_right: :expand_more,
  21. flag: :flag,
  22. option_horizontal: :more_horiz,
  23. option_vertical: :more_vert,
  24. pushpin: :pin_drop,
  25. baby_formula: :device_hub,
  26. log_out: :call_made,
  27. log_in: :call_received,
  28. explore: :explore,
  29. remove: :close,
  30. expand: :expand_more,
  31. collapse_down: :expand_less,
  32. globe: :public,
  33. check_circle_o: nil,
  34. commenting: :comment
  35. },
  36. font_awesome: {
  37. option_horizontal: :ellipsis_h,
  38. pushpin: "thumb-tack",
  39. globe: :globe,
  40. zoom_out: "search-minus",
  41. close: :remove,
  42. check_circle_o: "check-circle-o",
  43. check_circe: "check-circle",
  44. reorder: "align-justify",
  45. commenting: :commenting
  46. },
  47. glyphicon: {
  48. option_horizontal: "option-horizontal",
  49. option_vertical: "option-vertical",
  50. triangle_left: "triangle-left",
  51. triangle_right: "triangle-right",
  52. baby_formula: "baby-formula",
  53. log_out: "log-out",
  54. log_in: "log-in",
  55. collapse_down: "collapse-down",
  56. globe: :globe,
  57. zoom_out: "zoom-out",
  58. close: :remove,
  59. new_window: "new-window",
  60. history: :time,
  61. check_circle_o: "ok-circle",
  62. check_circle: "ok-sign",
  63. reorder: "align-justify"
  64. }
  65. }.freeze
  66. 1 def icon_class library, icon
  67. 28 ICON_MAP[library][icon] || icon
  68. end
  69. 1 def material_icon icon, opts={}
  70. 18 universal_icon_tag icon, :material, opts
  71. end
  72. 1 def glyphicon icon, opts={}
  73. universal_icon_tag icon, :glyphicon, opts
  74. end
  75. 1 def fa_icon icon, opts={}
  76. 2 universal_icon_tag icon, :font_awesome, opts
  77. end
  78. 1 def icon_tag icon, opts={}
  79. 8 opts = { class: opts } unless opts.is_a? Hash
  80. 8 library = opts.delete(:library) || default_icon_library
  81. 8 universal_icon_tag icon, library, opts
  82. end
  83. 1 def universal_icon_tag icon, icon_library=default_icon_library, opts={}
  84. 28 return "" unless icon.present?
  85. 28 opts = { class: opts } unless opts.is_a? Hash
  86. 28 icon_method = "#{icon_library}_icon_tag"
  87. 28 send icon_method, icon, opts
  88. end
  89. 1 def default_icon_library
  90. 8 :material
  91. end
  92. 1 def glyphicon_icon_tag icon, opts={}
  93. prepend_class opts, "glyphicon glyphicon-#{icon_class(:glyphicon, icon)}"
  94. wrap_with :span, "", opts.merge("aria-hidden": true)
  95. end
  96. 1 def font_awesome_icon_tag icon, opts={}
  97. 2 prepend_class opts, "fa fa-#{icon_class(:font_awesome, icon)}"
  98. 2 wrap_with :i, "", opts
  99. end
  100. 1 def material_icon_tag icon, opts={}
  101. 26 add_class opts, "material-icons"
  102. 26 wrap_with :i, icon_class(:material, icon), opts
  103. end
  104. end
  105. end;end;end;end;end;
  106. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/all/bootstrap/icon.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/navbar.rb

33.33% lines covered

33 relevant lines. 11 lines covered and 22 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module Bootstrap;
  3. # Set: All cards (Bootstrap, Navbar)
  4. #
  5. 1 module Navbar;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/all/bootstrap/navbar.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. # Options
  10. # @param opts [Hash]
  11. # @option opts [String, Hash<name, href>] brand
  12. # @option opts [String] class
  13. # @option opts [Boolean] no_collapse
  14. # @option opts [:left, :right] toggle_align
  15. 1 def navbar id, opts={}
  16. nav_opts = opts[:navbar_opts] || {}
  17. nav_opts[:class] ||= opts[:class]
  18. add_class nav_opts,
  19. "navbar navbar-dark bg-#{opts.delete(:navbar_type) || 'primary'}"
  20. content = yield
  21. if opts[:no_collapse]
  22. navbar_nocollapse content, nav_opts
  23. else
  24. navbar_responsive id, content, opts, nav_opts
  25. end
  26. end
  27. 1 def navbar_nocollapse content, nav_opts
  28. # content = wrap_with(:div, content)
  29. wrap_with :nav, content, nav_opts
  30. end
  31. 1 def navbar_responsive id, content, opts, nav_opts
  32. opts[:toggle_align] ||= :right
  33. wrap_with :nav, nav_opts do
  34. [
  35. navbar_header(opts[:brand]),
  36. navbar_toggle(id, opts[:toggle_align]),
  37. wrap_with(:div, class: "collapse navbar-collapse",
  38. id: "navbar-collapse-#{id}") { content }
  39. ]
  40. end
  41. end
  42. 1 def navbar_header brand
  43. return "" unless brand
  44. if brand.is_a? String
  45. "<span class='navbar-brand'>#{brand}</span>"
  46. else
  47. link = brand[:href] || "#"
  48. "<a class='navbar-brand' href='#{link}#'>#{brand[:name]}</a>"
  49. end
  50. end
  51. 1 def navbar_toggle id, align
  52. content ||= %(<span class="navbar-toggler-icon"></span>)
  53. <<-HTML
  54. <button class="navbar-toggler navbar-toggler-#{align}" type="button" data-toggle="collapse" data-target="#navbar-collapse-#{id}" aria-controls="navbar-collapse-#{id}" aria-expanded="false" aria-label="Toggle navigation">
  55. #{content}
  56. </button>
  57. HTML
  58. end
  59. 1 def breadcrumb items
  60. wrap_with :ol, class: "breadcrumb" do
  61. items.map do |item|
  62. wrap_with :li, item, class: "breadcrumb-item"
  63. end.join
  64. end
  65. end
  66. end
  67. end;end;end;end;end;
  68. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/all/bootstrap/navbar.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/table.rb

29.09% lines covered

55 relevant lines. 16 lines covered and 39 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module Bootstrap;
  3. # Set: All cards (Bootstrap, Table)
  4. #
  5. 1 module Table;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/all/bootstrap/table.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 class TableHelper
  10. 1 def initialize format, content, opts={}
  11. @format = format
  12. @div_table = opts.delete :div_table
  13. @header = initialize_header opts[:header], content
  14. @rows = content
  15. @opts = opts
  16. @format.add_class opts, :table
  17. end
  18. 1 def render
  19. tag :table, class: @opts[:class] do
  20. [header, body]
  21. end
  22. end
  23. 1 def header
  24. return unless @header
  25. tag :thead do
  26. tag :tr do
  27. @header.map do |item|
  28. tag(:th) { item }
  29. end.join "\n"
  30. end
  31. end
  32. end
  33. 1 def body
  34. tag :tbody do
  35. @rows.map do |row_content|
  36. row row_content
  37. end.join "\n"
  38. end
  39. end
  40. 1 def row row
  41. row_data, row_class =
  42. case row
  43. when Hash then
  44. [row.delete(:content), row]
  45. else
  46. [row, {}]
  47. end
  48. row_content =
  49. if row_data.is_a?(Array)
  50. row_data.map { |item| cell item }.join "\n"
  51. else
  52. row_data
  53. end
  54. tag :tr, row_content, row_class
  55. end
  56. 1 def cell cell
  57. if cell.is_a? Hash
  58. content = cell.delete(:content).to_s
  59. tag :td, cell do
  60. content
  61. end
  62. else
  63. tag :td do
  64. String(cell)
  65. end
  66. end
  67. end
  68. 1 def tag elem, content_or_opts={}, opts={}, &block
  69. if @div_table
  70. if content_or_opts.is_a? Hash
  71. @format.add_class content_or_opts, elem
  72. else
  73. @format.add_class opts, elem
  74. end
  75. elem = :div
  76. end
  77. @format.wrap_with elem, content_or_opts, opts, &block
  78. end
  79. 1 private
  80. 1 def initialize_header header, content
  81. case header
  82. when Array then header
  83. when nil then nil
  84. else content.shift
  85. end
  86. end
  87. end
  88. # @param [Array<Array,String>] content the content for the table. Accepts
  89. # strings or arrays for each row.
  90. # @param [Hash] opts
  91. # @option opts [String, Array] :header use first row of content as header or
  92. # value of this option if it is a string
  93. # @return [HTML] bootstrap table
  94. 1 def table content, opts={}
  95. TableHelper.new(self, content, opts).render
  96. end
  97. end
  98. end;end;end;end;end;
  99. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/all/bootstrap/table.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/tabs.rb

100.0% lines covered

9 relevant lines. 9 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module Bootstrap;
  3. # Set: All cards (Bootstrap, Tabs)
  4. #
  5. 1 module Tabs;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/all/bootstrap/tabs.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. # @param tab_hash [Hash] keys are the tab names
  10. # Each value can be either a String or a Hash.
  11. # If a Hash can contain the following keys:
  12. # :title - the label to appear in the clickable tab nav.
  13. # if title is not specified, the key is used
  14. # :content - body of tab pane
  15. # :button_attr - attributes for button link in tab nav.
  16. #
  17. # If using lazy loading (see :load below), the following options also apply
  18. # :path - explicit path to use for tab pane
  19. # :view - card view from which to auto-construct path (if missing, uses key)
  20. #
  21. # If the value is a String, it is treated as the tab content for static tabs and
  22. # the view for lazy tabs
  23. #
  24. # @param active_name [String] label of the tab that should be active at the
  25. #
  26. # @param [Hash] args options
  27. # @option args [String] :tab_type ('tabs') use pills or tabs
  28. # @option args [Hash] :panel_attr html args used for the panel div
  29. # @option args [Hash] :pane_attr html args used for the pane div
  30. # @option args [Hash] :load. `:lazy` for lazy-loading tabs
  31. #
  32. # @param [Block] block content of the active tab (for lazy-loading)
  33. # beginning (default is the first)
  34. #
  35. # @return [HTML] bootstrap tabs element with all content preloaded
  36. 1 def tabs tab_hash, active_name=nil, args={}, &block
  37. 1 klass = args[:load] == :lazy ? Card::LazyTab : Card::Tab
  38. 1 args.reverse_merge!(
  39. panel_attr: {},
  40. pane_attr: {},
  41. tab_type: "tabs",
  42. block: block,
  43. tab_objects: Card::Tab.tab_objects(self, tab_hash, active_name, klass)
  44. )
  45. 1 haml :tab_panel, args
  46. end
  47. end
  48. end;end;end;end;end;
  49. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/all/bootstrap/tabs.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/all/bootstrap/wrapper.rb

93.33% lines covered

15 relevant lines. 14 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module Bootstrap;
  3. # Set: All cards (Bootstrap, Wrapper)
  4. #
  5. 1 module Wrapper;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/all/bootstrap/wrapper.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def frame
  10. 20 class_up "d0-card-header" , "card-header"
  11. 20 class_up "d0-card-body", "card-body card-text"
  12. 20 super
  13. end
  14. 1 def standard_frame slot=true
  15. 20 if panel_state
  16. class_up "d0-card-frame", "card bg-#{panel_state} text-white"
  17. else
  18. 20 class_up "d0-card-frame", "card"
  19. end
  20. 20 super
  21. end
  22. 1 def panel_state
  23. end
  24. end
  25. end;end;end;end;end;
  26. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/all/bootstrap/wrapper.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/all/rich_bootstrap.rb

83.33% lines covered

12 relevant lines. 10 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (RichBootstrap)
  4. #
  5. 1 module RichBootstrap;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/all/rich_bootstrap.rb"; end
  8. 1 def read_bootstrap_variables
  9. path = ::File.expand_path(
  10. "#{mod_root :bootstrap}/vendor/bootstrap/scss/_variables.scss", __FILE__
  11. )
  12. ::File.exist?(path) ? ::File.read(path) : ""
  13. end
  14. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  15. 1 view :closed do
  16. 1 class_up "d0-card-body", "closed-content"
  17. 1 super()
  18. end
  19. 1 include Bootstrapper
  20. end
  21. end;end;end;end;
  22. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/all/rich_bootstrap.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/self/bootstrap_core.rb

100.0% lines covered

11 relevant lines. 11 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "BootstrapCore"
  4. #
  5. 1 module BootstrapCore;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/bootstrap_core.rb"; end
  8. 1 include_set Abstract::BootstrapCodeFile
  9. 1 def load_stylesheets
  10. 1 add_bs_stylesheet "variables"
  11. 1 add_bs_subdir "mixins"
  12. 1 %w[ print reboot type images code grid tables forms buttons transitions dropdown
  13. button-group input-group custom-forms nav navbar card breadcrumb pagination badge
  14. jumbotron alert progress media list-group close modal tooltip popover carousel
  15. ].each do |name|
  16. 30 add_bs_stylesheet name
  17. end
  18. 1 add_bs_subdir "utilities"
  19. end
  20. end;end;end;end;
  21. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/bootstrap_core.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/self/bootstrap_functions.rb

100.0% lines covered

7 relevant lines. 7 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "BootstrapFunctions"
  4. #
  5. 1 module BootstrapFunctions;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/bootstrap_functions.rb"; end
  8. 1 include_set Abstract::BootstrapCodeFile
  9. 1 def load_stylesheets
  10. 1 add_bs_stylesheet "functions"
  11. end
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/bootstrap_functions.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/self/font_awesome.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "FontAwesome"
  4. #
  5. 1 module FontAwesome;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/font_awesome.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 Self::StyleLibraries.add_item :font_awesome
  10. end;end;end;end;
  11. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/font_awesome.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/self/material_icons.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "MaterialIcons"
  4. #
  5. 1 module MaterialIcons;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/material_icons.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 Self::StyleLibraries.add_item :material_icons
  10. end;end;end;end;
  11. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/material_icons.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/self/script_bootstrap.rb

80.0% lines covered

10 relevant lines. 8 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ScriptBootstrap"
  4. #
  5. 1 module ScriptBootstrap;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/script_bootstrap.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 Self::ScriptLibraries.add_item :script_bootstrap
  10. 1 def source_dir
  11. ""
  12. end
  13. 1 def source_files
  14. %w[vendor/bootstrap/dist/js/bootstrap.bundle.js
  15. lib/javascript/bootstrap_modal_decko.js
  16. vendor/bootstrap-colorpicker/dist/js/bootstrap-colorpicker.min.js]
  17. end
  18. end;end;end;end;
  19. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/script_bootstrap.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/self/script_load_select2.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ScriptLoadSelect2"
  4. #
  5. 1 module ScriptLoadSelect2;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/script_load_select2.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 Self::ScriptMods.add_item :script_load_select2
  10. end;end;end;end;
  11. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/script_load_select2.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/self/script_select2.rb

80.0% lines covered

10 relevant lines. 8 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ScriptSelect2"
  4. #
  5. 1 module ScriptSelect2;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/script_select2.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 Self::ScriptLibraries.add_item :script_select2
  10. 1 def source_files
  11. # full version of select2 is needed to support containerCssClass config option
  12. # which we need for select2_bootstrap to work properly
  13. "vendor/select2/dist/js/select2.full.min.js"
  14. end
  15. 1 def source_dir
  16. ""
  17. end
  18. end;end;end;end;
  19. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/script_select2.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/self/smartmenu_css.rb

85.71% lines covered

7 relevant lines. 6 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "SmartmenuCss"
  4. #
  5. 1 module SmartmenuCss;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/smartmenu_css.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 def source_files
  10. "startmenu.css"
  11. end
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/smartmenu_css.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/self/smartmenu_js.rb

85.71% lines covered

7 relevant lines. 6 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "SmartmenuJs"
  4. #
  5. 1 module SmartmenuJs;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/smartmenu_js.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 def source_files
  10. "startmenu.js"
  11. end
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/smartmenu_js.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/self/style_bootstrap_cards.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "StyleBootstrapCards"
  4. #
  5. 1 module StyleBootstrapCards;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/style_bootstrap_cards.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. end;end;end;end;
  10. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/style_bootstrap_cards.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/self/style_bootstrap_colorpicker.rb

100.0% lines covered

8 relevant lines. 8 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "StyleBootstrapColorpicker"
  4. #
  5. 1 module StyleBootstrapColorpicker;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/style_bootstrap_colorpicker.rb"; end
  8. 1 include_set Abstract::BootstrapCodeFile
  9. 1 Self::StyleLibraries.add_item :style_bootstrap_colorpicker
  10. 1 def load_stylesheets
  11. 1 add_stylesheet_file "vendor/bootstrap-colorpicker/src/sass/_colorpicker.scss"
  12. end
  13. end;end;end;end;
  14. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/style_bootstrap_colorpicker.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/self/style_select2.rb

100.0% lines covered

10 relevant lines. 10 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "StyleSelect2"
  4. #
  5. 1 module StyleSelect2;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/style_select2.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 Self::StyleLibraries.add_item :style_select2
  10. 1 def source_files
  11. 2 ["vendor/select2/dist/css/select2.css", "lib/stylesheets/style_select2_bootstrap.scss"]
  12. end
  13. 1 def source_dir
  14. 4 ""
  15. end
  16. end;end;end;end;
  17. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/style_select2.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/self/style_select2_bootstrap.rb

100.0% lines covered

5 relevant lines. 5 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "StyleSelect2Bootstrap"
  4. #
  5. 1 module StyleSelect2Bootstrap;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/style_select2_bootstrap.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. end;end;end;end;
  10. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/self/style_select2_bootstrap.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/type/bootswatch_skin.rb

100.0% lines covered

9 relevant lines. 9 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "BootswatchSkin" cards
  4. #
  5. 1 module BootswatchSkin;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/type/bootswatch_skin.rb"; end
  8. 1 include_set Abstract::BootswatchTheme
  9. # override to customize the theme or to make it customizable
  10. # @return [Card, String, Array<Card, String>] strings must be valid (s)css; cards
  11. # must be of type (S)CSS
  12. 1 def variables_content
  13. 1 scss_from_theme_file :variables
  14. end
  15. # override to customize the theme or to make it customizable
  16. # @return [Card, String, Array<Card,String>] strings must be valid (s)css; cards
  17. # must be of type (S)CSS
  18. 1 def stylesheets_content
  19. 1 scss_from_theme_file :bootswatch
  20. end
  21. end;end;end;end;
  22. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/type/bootswatch_skin.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/type/customized_bootswatch_skin.rb

41.18% lines covered

68 relevant lines. 28 lines covered and 40 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "CustomizedBootswatchSkin" cards
  4. #
  5. 1 module CustomizedBootswatchSkin;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/type/customized_bootswatch_skin.rb"; end
  8. 1 include_set Abstract::BootswatchTheme
  9. 1 card_accessor :colors
  10. 1 card_accessor :variables
  11. 1 card_accessor :stylesheets
  12. 1 def top_level_item_cards
  13. cards = PRE_VARIABLES_CARD_NAMES.map { |n| Card[n] }
  14. cards += [colors_card, variables_card]
  15. cards += POST_VARIABLES_CARD_NAMES.map { |n| Card[n] }
  16. cards << stylesheets_card
  17. cards
  18. end
  19. 1 def editable_item_cards
  20. [colors_card, variables_card, stylesheets_card]
  21. end
  22. 1 def variables_card_names
  23. %i[colors variables].map { |s| Card.fetch_name name, s }
  24. end
  25. 1 def stylesheets_card_names
  26. [Card.fetch_name(name, :stylesheets)]
  27. end
  28. 1 def theme_card_name
  29. "#{theme_name} skin"
  30. end
  31. 1 def theme_name
  32. Env.params[:theme].present? && Env.params[:theme]
  33. end
  34. 1 def theme_codename
  35. theme_name && "#{theme_name}_skin".to_sym
  36. end
  37. 1 event :validate_theme_template, :validate, on: :create do
  38. if theme_name
  39. if Card.fetch_type_id(theme_card_name) != Card::BootswatchSkinID
  40. errors.add :abort, tr(:not_valid_theme, theme_name: theme_name)
  41. elsif !Dir.exist? source_dir
  42. puts method(:source_dir).source_location
  43. errors.add :abort, tr(:cannot_source_theme, theme_name: theme_name)
  44. end
  45. end
  46. end
  47. 1 event :initialize_because_of_type_change, :prepare_to_store,
  48. on: :update, changed: :type do
  49. initialize_theme old_skin_items
  50. end
  51. 1 def old_skin_items
  52. skin = Card.new(type: :pointer, content: db_content_before_act)
  53. skin.drop_item "bootstrap default skin"
  54. skin.item_names
  55. end
  56. 1 event :copy_theme, :prepare_to_store, on: :create do
  57. initialize_theme
  58. end
  59. 1 def initialize_theme style_item_names=nil
  60. add_subfield :colors, type_id: Card::ScssID
  61. add_variables_subfield
  62. add_stylesheets_subfield style_item_names
  63. end
  64. 1 def add_stylesheets_subfield style_items=nil
  65. opts = { type_id: Card::SkinID }
  66. if theme_name
  67. theme_style = add_bootswatch_subfield
  68. opts[:content] = "[[#{theme_style.name}]]"
  69. end
  70. if style_items
  71. opts[:content] = [opts[:content], style_items].flatten.compact.to_pointer_content
  72. end
  73. add_subfield :stylesheets, opts
  74. end
  75. 1 def add_variables_subfield
  76. theme_content = content_from_theme(:variables)
  77. default_content = read_bootstrap_variables
  78. add_subfield :variables,
  79. type_id: Card::ScssID,
  80. content: "#{theme_content}\n\n\n#{default_content}"
  81. end
  82. 1 def add_bootswatch_subfield
  83. add_subfield :bootswatch, type_id: Card::ScssID,
  84. content: content_from_theme(:bootswatch)
  85. end
  86. 1 def theme_card
  87. @theme_card ||= theme_codename ? Card[theme_codename] : nil
  88. end
  89. 1 def content_from_theme subfield
  90. theme_card&.scss_from_theme_file subfield
  91. end
  92. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  93. 1 def edit_fields
  94. [[:colors, { title: "" }],
  95. [:variables, { title: "Variables" }],
  96. [:stylesheets, { title: "Styles" }]]
  97. end
  98. 1 view :one_line_content do
  99. ""
  100. end
  101. end
  102. end;end;end;end;
  103. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/type/customized_bootswatch_skin.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/type/customized_bootswatch_skin/html_views.rb

65.22% lines covered

23 relevant lines. 15 lines covered and 8 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Type; module CustomizedBootswatchSkin;
  3. # Set: All "CustomizedBootswatchSkin+HtmlViews" cards (HtmlViews)
  4. #
  5. 1 module HtmlViews;
  6. 1 extend Card::Set
  7. 2 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/type/customized_bootswatch_skin/html_views.rb"; end
  8. 1 include_set Abstract::Media
  9. 1 include_set Abstract::BsBadge
  10. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  11. 1 view :menu do
  12. ""
  13. end
  14. 1 def short_content
  15. ""
  16. # labeled_badge card.item_count, "items"
  17. # "#{card.item_count} items"
  18. end
  19. 1 view :core, template: :haml
  20. 1 info_bar_cols 6, 3, 3
  21. 1 before :bar do
  22. super()
  23. voo.show :edit_button, :bar_middle
  24. class_up "bar-middle", "p-3 align-items-center p-0"
  25. end
  26. 1 view :bar_right do
  27. render(:short_content)
  28. end
  29. 1 before :bar_nav do
  30. voo.hide :edit_link
  31. end
  32. 1 view :bar_bottom do
  33. render_core
  34. end
  35. end
  36. end;end;end;end;end;
  37. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/type/customized_bootswatch_skin/html_views.rb ~~

card/tmpsets/set/mod017-card-mod-bootstrap/type_plus_right/customized_bootswatch_skin/colors.rb

44.23% lines covered

52 relevant lines. 23 lines covered and 29 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class TypePlusRight; module CustomizedBootswatchSkin;
  3. # Set: All "+Colors" cards on "CustomizedBootswatchSkin" cards
  4. #
  5. 1 module Colors;
  6. 1 extend Card::Set
  7. 3 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/type_plus_right/customized_bootswatch_skin/colors.rb"; end
  8. VARIABLE_NAMES = {
  9. 1 colors: %i[blue indigo purple pink red orange yellow green teal cyan
  10. white gray-100 gray-200 gray-300 gray-400 gray-500 gray-600 gray-700 gray-800
  11. gray-900 black],
  12. theme_colors: %i[primary secondary success info warning danger light dark
  13. body-bg body-color]
  14. }.freeze
  15. # temporarily removed: link-color card-bg card-cap-bg
  16. # bootstrap default for link-color uses the theme-color function which
  17. # has to be defined between the theme-colors and that variable
  18. # (see bootstrap's _variables.scss)
  19. # TODO: deal with that
  20. # @param name [String] a scss variable name (it can start with a $)
  21. 1 def variable_value name
  22. value_from_scss(name, content) ||
  23. value_from_variables_card(name) ||
  24. default_value_from_bootstrap(name)
  25. end
  26. 1 def value_from_scss name, source
  27. name = name.to_s
  28. name = name[1..-1] if name.start_with?("$")
  29. source.match(definition_regex(name))&.capture(:value)
  30. end
  31. 1 def value_from_variables_card name
  32. return unless (var_card = left.variables_card) && var_card.content.present?
  33. value_from_scss name, var_card.content
  34. end
  35. 1 def definition_regex name
  36. /^(?<before>\s*\$#{name}\:\s*)(?<value>.+?)(?<after> !default;)$/
  37. end
  38. 1 def default_value_from_bootstrap name
  39. value_from_scss name, bootstrap_variables_scss
  40. end
  41. 1 def bootstrap_variables_scss
  42. @bootstrap_variables_scss ||= read_bootstrap_variables
  43. end
  44. 1 def colors
  45. @colors ||= variable_group_with_values :colors
  46. end
  47. 1 def theme_colors
  48. @theme_colors ||= variable_group_with_values :theme_colors
  49. end
  50. 1 def variable_group_with_values group
  51. VARIABLE_NAMES[group].each_with_object({}) do |name, h|
  52. h[name] = variable_value name
  53. end
  54. end
  55. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  56. 1 view :input, template: :haml do
  57. @colors = card.colors
  58. @theme_colors = card.theme_colors
  59. end
  60. 1 def theme_color_picker name, value
  61. # value = value[1..-1] if value.start_with? "$"
  62. options = VARIABLE_NAMES[:colors].map { |var| "$#{var}" }
  63. options << value unless options.include? value
  64. select_tag "theme_colors[#{name}]", options_for_select(options, value),
  65. class: "tags form-control"
  66. end
  67. 1 before :bar_right do
  68. voo.show :edit_button
  69. end
  70. 1 view :core, template: :haml do
  71. @colors = card.theme_colors.reject { |k, _v| k.in? %i[body-bg body-color] }
  72. end
  73. 1 view :bar_middle do
  74. <<-HTML
  75. <div class="colorpicker-element">
  76. <div class="input-group-addon">
  77. <span class="bg-body border p-1">Text</span>
  78. <span class="bg-dark text-light border p-1">Nav</span>
  79. <i class="bg-primary"></i>
  80. <i class="bg-secondary"></i>
  81. </div>
  82. </div>
  83. HTML
  84. end
  85. end
  86. 1 event :translate_variables_to_scss, :prepare_to_validate, on: :update do
  87. replace_values :colors
  88. replace_values :theme_colors
  89. end
  90. 1 def replace_values group, prefix=""
  91. values = variable_values_from_params group
  92. values.each_pair do |name, val|
  93. if content.match definition_regex(name)
  94. content.gsub! definition_regex(name), "\\k<before>#{prefix}#{val}\\k<after>"
  95. else
  96. self.content += "$#{name}: #{prefix}#{val} !default;\n"
  97. end
  98. end
  99. end
  100. 1 def variable_values_from_params group
  101. Env.params.dig(group)&.slice(*VARIABLE_NAMES[group]) || {}
  102. end
  103. end;end;end;end;end;
  104. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-bootstrap/set/type_plus_right/customized_bootswatch_skin/colors.rb ~~

card/tmpsets/set/mod018-card-mod-history/all/history.rb

75.0% lines covered

56 relevant lines. 42 lines covered and 14 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (History)
  4. #
  5. 1 module History;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-history/set/all/history.rb"; end
  8. 1 event :update_ancestor_timestamps, :integrate do
  9. 314 ids = history_ancestor_ids
  10. 314 return unless ids.present?
  11. 6 Card.where(id: ids).update_all(updater_id: Auth.current_id, updated_at: Time.now)
  12. 12 ids.map { |anc_id| Card.expire anc_id.cardname }
  13. end
  14. # track history (acts, actions, changes) on this card
  15. 1 def history?
  16. 666 true
  17. end
  18. # all cards whose acts are considered part of this card's history
  19. 1 def history_card_ids
  20. nestee_ids << id
  21. end
  22. # all cards who are considered updated if this card's was updated
  23. 1 def history_parent_ids
  24. 640 nester_ids
  25. end
  26. 1 def history_ancestor_ids recursion_level=0
  27. 320 return [] if recursion_level > 5
  28. 320 ids = history_parent_ids +
  29. 6 history_parent_ids.map { |id| Card[id].history_ancestor_ids(recursion_level + 1) }
  30. 320 ids.flatten
  31. end
  32. # ~~FIXME~~: optimize (no need to instantiate all actions and changes!)
  33. # Nothing is instantiated here. ActiveRecord is much smarter than you think.
  34. # Methods like #empty? and #size make sql queries if their receivers are not already
  35. # loaded -pk
  36. 1 def first_change?
  37. # = update or delete
  38. 294 @current_action.action_type != :create && action_count == 2 &&
  39. create_action.card_changes.empty?
  40. end
  41. 1 def first_create?
  42. 294 @current_action.action_type == :create && action_count == 1
  43. end
  44. 1 def action_count
  45. 294 Card::Action.where(card_id: @current_action.card_id).count
  46. end
  47. # card has account that is responsible for prior acts
  48. 1 def has_edits?
  49. Card::Act.where(actor_id: id).where("card_id IS NOT NULL").present?
  50. end
  51. 1 def changed_fields
  52. 421 Card::Change::TRACKED_FIELDS & (changed_attribute_names_to_save | saved_changes.keys)
  53. end
  54. 1 def nestee_ids
  55. requiring_id { @nestee_ids ||= nesting_ids(:referee_id, :referer_id) }
  56. end
  57. 1 def nester_ids
  58. 1280 requiring_id { @nester_ids ||= nesting_ids(:referer_id, :referee_id) }
  59. end
  60. 1 def diff_args
  61. { diff_format: :text }
  62. end
  63. # Delete all changes and old actions and make the last action the create action
  64. # (that way the changes for that action will be created with the first update)
  65. 1 def make_last_action_the_initial_action
  66. delete_all_changes
  67. old_actions.delete_all
  68. last_action.update! action_type: :create
  69. end
  70. 1 def clear_history
  71. delete_all_changes
  72. delete_old_actions
  73. end
  74. 1 def delete_old_actions
  75. old_actions.delete_all
  76. end
  77. 1 def delete_all_changes
  78. Card::Change.where(card_action_id: all_action_ids).delete_all
  79. end
  80. 1 def save_content_draft content
  81. super
  82. acts.create do |act|
  83. act.ar_actions.build(draft: true, card_id: id, action_type: :update)
  84. .card_changes.build(field: :db_content, value: content)
  85. end
  86. end
  87. 1 private
  88. 1 def nesting_ids return_field, where_field
  89. 302 Card::Reference.select(return_field).distinct.where(
  90. ref_type: "I", where_field => id
  91. ).pluck(return_field).compact
  92. end
  93. 1 def requiring_id
  94. 640 id ? yield : (return [])
  95. end
  96. end;end;end;end;
  97. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-history/set/all/history.rb ~~

card/tmpsets/set/mod018-card-mod-history/all/history/act_listing.rb

36.76% lines covered

68 relevant lines. 25 lines covered and 43 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module History;
  3. # Set: All cards (History, ActListing)
  4. #
  5. 1 module ActListing;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-history/set/all/history/act_listing.rb"; end
  8. 1 ACTS_PER_PAGE = Card.config.acts_per_page
  9. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  10. 1 def act_from_context
  11. if (act_id = params["act_id"])
  12. Act.find(act_id) || raise(Card::NotFound, "act not found")
  13. else
  14. card.last_action.act
  15. end
  16. end
  17. # used (by history and recent)for rendering act lists with legend and paging
  18. #
  19. # @param acts [ActiveRecord::Relation] relation that will return acts objects
  20. # @param context [Symbol] :relative or :absolute
  21. # @param draft_legend [Symbol] :show or :hide
  22. 1 def acts_layout acts, context, draft_legend=:hide
  23. bs_layout container: false, fluid: false do
  24. html _render_act_legend(draft_legend => :draft_legend)
  25. row(12) { act_list acts, context }
  26. row(12) { act_paging acts, context }
  27. end
  28. end
  29. 1 def act_list acts, context
  30. act_accordion acts, context do |act, seq|
  31. fmt = context == :relative ? self : act.card.format(:html)
  32. fmt.act_listing act, seq, context
  33. end
  34. end
  35. 1 def act_listing act, seq=nil, context=nil
  36. opts = act_listing_opts_from_params(seq)
  37. opts[:slot_class] = "revision-#{act.id} history-slot list-group-item"
  38. context ||= (params[:act_context] || :absolute).to_sym
  39. act_renderer(context).new(self, act, opts).render
  40. end
  41. # TODO: consider putting all these under one top-level param, eg:
  42. # act: { seq: X, diff: [show/hide], action_view: Y }
  43. 1 def act_listing_opts_from_params seq
  44. { act_seq: (seq || params["act_seq"]),
  45. action_view: (params["action_view"] || "summary").to_sym,
  46. hide_diff: params["hide_diff"].to_s.strip == "true" }
  47. end
  48. 1 def act_accordion acts, context, &block
  49. accordion_group acts_for_accordion(acts, context, &block), nil, class: "clear-both"
  50. end
  51. 1 def acts_for_accordion acts, context
  52. clean_acts(current_page_acts(acts)).map do |act|
  53. with_act_seq(context, acts) do |seq|
  54. yield act, seq
  55. end
  56. end
  57. end
  58. 1 def with_act_seq context, acts
  59. yield(context == :absolute ? nil : current_act_seq(acts))
  60. end
  61. 1 def current_act_seq acts
  62. @act_seq = @act_seq ? (@act_seq -= 1) : act_list_starting_seq(acts)
  63. end
  64. 1 def clean_acts acts
  65. # FIXME: if we get rid of bad act data, this will not be necessary
  66. # The current
  67. acts.select(&:card)
  68. end
  69. 1 def current_page_acts acts
  70. acts.page(acts_page_from_params).per acts_per_page
  71. end
  72. 1 def act_list_starting_seq acts
  73. acts.size - (acts_page_from_params - 1) * acts_per_page
  74. end
  75. 1 def acts_per_page
  76. @acts_per_page || ACTS_PER_PAGE
  77. end
  78. 1 def acts_page_from_params
  79. @acts_page_from_params ||= params["page"].present? ? params["page"].to_i : 1
  80. end
  81. 1 def act_paging acts, context
  82. wrap_with :div, class: "slotter btn-sm" do
  83. acts = current_page_acts acts
  84. opts = { remote: true, theme: "twitter-bootstrap-4" }
  85. opts[:total_pages] = 10 if limited_paging? context
  86. paginate acts, opts
  87. end
  88. end
  89. 1 def limited_paging? context
  90. context == :absolute && Act.count > 1000
  91. end
  92. 1 def action_icon action_type, extra_class=nil
  93. icon = case action_type
  94. when :create then :add_circle
  95. when :update then :pencil
  96. when :delete then :remove_circle
  97. when :draft then :wrench
  98. end
  99. icon_tag icon, extra_class
  100. end
  101. 1 private
  102. 1 def act_renderer context
  103. case context
  104. when :absolute
  105. Act::ActRenderer::AbsoluteActRenderer
  106. when :bridge
  107. Act::ActRenderer::BridgeActRenderer
  108. else # relative
  109. Act::ActRenderer::RelativeActRenderer
  110. end
  111. end
  112. end
  113. end;end;end;end;end;
  114. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-history/set/all/history/act_listing.rb ~~

card/tmpsets/set/mod018-card-mod-history/all/history/actions.rb

46.27% lines covered

67 relevant lines. 31 lines covered and 36 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module History;
  3. # Set: All cards (History, Actions)
  4. #
  5. # -*- encoding : utf-8 -*-
  6. 1 module Actions;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-history/set/all/history/actions.rb"; end
  9. 1 def all_action_ids
  10. Card::Action.where(card_id: id).pluck :id
  11. end
  12. 1 def action_from_id action_id
  13. 26 return unless action_id.is_a?(Integer) || action_id =~ /^\d+$/
  14. # if not an integer revision id is probably a mod (e.g. if you request
  15. # files/:logo/standard.png)
  16. action = Action.fetch action_id
  17. return unless action.card_id == id
  18. action
  19. end
  20. 1 def old_actions
  21. actions.where("id != ?", last_action_id)
  22. end
  23. 1 def create_action
  24. 293 @create_action ||= actions.first
  25. end
  26. 1 def nth_action index
  27. 29 index = index.to_i
  28. 29 return unless id && index.positive?
  29. 3 Action.where("draft is not true AND card_id = #{id}")
  30. .order(:id).limit(1).offset(index - 1).first
  31. end
  32. 1 def new_content_action_id
  33. 159 return unless @current_action && current_action_changes_content?
  34. 32 @current_action.id
  35. end
  36. 1 def current_action_changes_content?
  37. 32 new_card? || @current_action.new_content? || db_content_is_changing?
  38. end
  39. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  40. 1 def action_from_context
  41. if (action_id = voo.action_id || params[:action_id])
  42. Action.fetch action_id
  43. else
  44. card.last_action
  45. end
  46. end
  47. 1 def action_content action, view_type
  48. return "" unless action.present?
  49. wrap do
  50. [action_content_toggle(action, view_type),
  51. content_diff(action, view_type)]
  52. end
  53. end
  54. 1 def content_diff action, view_type
  55. diff = action.new_content? && content_changes(action, view_type)
  56. return "<i>empty</i>" unless diff.present?
  57. diff
  58. end
  59. 1 def action_content_toggle action, view_type
  60. return unless show_action_content_toggle?(action, view_type)
  61. toggle_action_content_link action, view_type
  62. end
  63. 1 def show_action_content_toggle? action, view_type
  64. view_type == :expanded || action.summary_diff_omits_content?
  65. end
  66. 1 def toggle_action_content_link action, view_type
  67. other_view_type = view_type == :expanded ? :summary : :expanded
  68. css_class = "revision-#{action.card_act_id} float-right"
  69. link_to_view "action_#{other_view_type}",
  70. icon_tag(action_arrow_dir(view_type), class: "md-24"),
  71. class: css_class,
  72. path: { action_id: action.id, look_in_trash: true }
  73. end
  74. 1 def action_arrow_dir view_type
  75. view_type == :expanded ? :triangle_left : :triangle_right
  76. end
  77. 1 def revert_actions_link link_text, path_args, html_args={}
  78. return unless card.ok? :update
  79. path_args.reverse_merge! action: :update, look_in_trash: true, assign: true,
  80. card: { skip: :validate_renaming }
  81. html_args.reverse_merge! remote: true, method: :post, rel: "nofollow", path: path_args
  82. add_class html_args, "slotter"
  83. link_to link_text, html_args
  84. end
  85. 1 def action_legend
  86. types = %i[create update delete]
  87. legend = types.map do |action_type|
  88. "#{action_icon(action_type)} #{action_type}d"
  89. end
  90. legend << _render_draft_legend if voo.show?(:draft_legend)
  91. "<small>Actions: #{legend.join ' | '}</small>"
  92. end
  93. 1 def content_legend
  94. legend = [Card::Content::Diff.render_added_chunk("Additions"),
  95. Card::Content::Diff.render_deleted_chunk("Subtractions")]
  96. "<small>Content changes: #{legend.join ' | '}</small>"
  97. end
  98. 1 def content_changes action, diff_type, hide_diff=false
  99. if hide_diff
  100. action.raw_view
  101. else
  102. action.content_diff diff_type
  103. end
  104. end
  105. end
  106. end;end;end;end;end;
  107. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-history/set/all/history/actions.rb ~~

card/tmpsets/set/mod018-card-mod-history/all/history/acts.rb

75.0% lines covered

8 relevant lines. 6 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module History;
  3. # Set: All cards (History, Acts)
  4. #
  5. # all acts with actions on self and on cards included in self (ie, acts shown in history)
  6. 1 module Acts;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-history/set/all/history/acts.rb"; end
  9. 1 def history_acts
  10. @history_acts ||= Act.all_with_actions_on(history_card_ids, true).order id: :desc
  11. end
  12. 1 def draft_acts
  13. drafts.created_by(Card::Auth.current_id).map(&:act)
  14. end
  15. end;end;end;end;end;
  16. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-history/set/all/history/acts.rb ~~

card/tmpsets/set/mod018-card-mod-history/all/history/events.rb

84.0% lines covered

50 relevant lines. 42 lines covered and 8 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module History;
  3. # Set: All cards (History, Events)
  4. #
  5. # must be called on all actions and before :set_name, :process_subcards and
  6. 1 module Events;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-history/set/all/history/events.rb"; end
  9. # :validate_delete_children
  10. 1 event :assign_action, :initialize, when: :actionable? do
  11. 316 act = director.need_act
  12. 316 @current_action = Card::Action.create(
  13. card_act_id: act.id,
  14. action_type: action,
  15. 316 draft: (Env.params["draft"] == "true")
  16. )
  17. 316 if @supercard && @supercard != self
  18. 150 @current_action.super_action = @supercard.current_action
  19. end
  20. end
  21. # can we store an action? (can be overridden, eg in files)
  22. 1 def actionable?
  23. 650 history?
  24. end
  25. 1 event :detect_conflict, :validate, on: :update, when: :edit_conflict? do
  26. errors.add :conflict, tr(:error_not_latest_revision)
  27. end
  28. 1 def edit_conflict?
  29. 58 last_action_id_before_edit &&
  30. last_action_id_before_edit.to_i != last_action_id &&
  31. (la = last_action) &&
  32. la.act.actor_id != Auth.current_id
  33. end
  34. # stores changes in the changes table and assigns them to the current action
  35. # removes the action if there are no changes
  36. 1 event :finalize_action, :finalize, when: :finalize_action? do
  37. 303 if changed_fields.present?
  38. 294 @current_action.update! card_id: id
  39. # Note: #last_change_on uses the id to sort by date
  40. # so the changes for the create changes have to be created before the first change
  41. 294 store_card_changes_for_create_action if first_change?
  42. 294 store_card_changes unless first_create?
  43. # FIXME: a `@current_action.card` call here breaks specs in solid_cache_spec.rb
  44. 9 elsif @current_action.card_changes.reload.empty?
  45. 9 @current_action.delete
  46. 9 @current_action = nil
  47. end
  48. end
  49. # changes for the create action are stored after the first update
  50. 1 def store_card_changes_for_create_action
  51. 97 Card::Action.cache.delete "#{create_action.id}-changes"
  52. 97 store_each_history_field create_action.id do |field|
  53. 582 attribute_before_act field
  54. end
  55. end
  56. 1 def store_card_changes
  57. 118 store_each_history_field @current_action.id, changed_fields do |field|
  58. 153 self[field]
  59. end
  60. end
  61. 1 def store_each_history_field action_id, fields=nil
  62. 215 fields ||= Card::Change::TRACKED_FIELDS
  63. if false # Card::Change.supports_import?
  64. # attach.feature fails with this
  65. values = fields.map.with_index { |field, index| [index, yield(field), action_id] }
  66. Card::Change.import [:field, :value, :card_action_id], values #, validate: false
  67. else
  68. 215 fields.each do |field|
  69. 735 Card::Change.create field: field,
  70. value: yield(field),
  71. card_action_id: action_id
  72. end
  73. end
  74. end
  75. 1 def finalize_action?
  76. 318 actionable? && current_action
  77. end
  78. 1 event :rollback_actions, :prepare_to_validate, on: :update, when: :rollback_request? do
  79. update_args = process_revert_actions
  80. Env.params["revert_actions"] = nil
  81. update! update_args
  82. clear_drafts
  83. abort :success
  84. end
  85. 1 event :finalize_act, after: :finalize_action, when: :act_card? do
  86. 140 Card::Director.act.update! card_id: id
  87. end
  88. 1 event :remove_empty_act, :integrate_with_delay_final, when: :remove_empty_act? do
  89. # Card::Director.act.delete
  90. # Card::Director.act = nil
  91. end
  92. 1 def remove_empty_act?
  93. 314 act_card? && Director.act&.ar_actions&.reload&.empty?
  94. end
  95. end;end;end;end;end;
  96. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-history/set/all/history/events.rb ~~

card/tmpsets/set/mod018-card-mod-history/all/history/last.rb

65.45% lines covered

55 relevant lines. 36 lines covered and 19 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module History;
  3. # Set: All cards (History, Last)
  4. #
  5. 1 module Last;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-history/set/all/history/last.rb"; end
  8. 1 def acted_at
  9. last_act.acted_at
  10. end
  11. 1 def revised_at
  12. (last_action && (act = last_action.act) && act.acted_at) || Time.zone.now
  13. end
  14. 1 def last_change_on field, opts={}
  15. 1 action_id = extract_action_id(opts[:before] || opts[:not_after])
  16. # If there is only one action then there are no entries in the changes table,
  17. # so we can't do a sql search but the changes are accessible via the action.
  18. 1 if no_last_change? action_id, opts[:before]
  19. nil
  20. 1 elsif create_action_last_change? action_id
  21. create_action&.change field
  22. else
  23. 1 last_change_from_action_id action_id, field, opts
  24. end
  25. end
  26. 1 def no_last_change? action_id, before
  27. 1 before && action_id == create_action.id
  28. end
  29. 1 def create_action_last_change? action_id
  30. 1 action_id == create_action&.id || (!action_id && create_action&.sole?)
  31. end
  32. 1 def last_change_from_action_id action_id, field, opts
  33. 1 Change.joins(:action).where(
  34. last_change_sql_conditions(opts),
  35. card_id: id,
  36. action_id: action_id,
  37. field: Card::Change.field_index(field)
  38. ).order(:id).last
  39. end
  40. 1 def last_change_sql_conditions opts
  41. 1 cond = "card_actions.card_id = :card_id AND field = :field"
  42. 1 cond += " AND (draft is not true)" unless opts[:including_drafts]
  43. 1 operator = "<" if opts[:before]
  44. 1 operator = "<=" if opts[:not_after]
  45. 1 cond += " AND card_action_id #{operator} :action_id" if operator
  46. 1 cond
  47. end
  48. 1 def last_action_id
  49. 1 last_action&.id
  50. end
  51. 1 def last_action
  52. 7 actions.where("id IS NOT NULL").last
  53. end
  54. 1 def last_content_action
  55. last_change_on(:db_content)&.action
  56. end
  57. 1 def last_content_action_id
  58. last_change_on(:db_content)&.card_action_id
  59. end
  60. 1 def last_actor
  61. last_act.actor
  62. end
  63. 1 def last_act
  64. @last_act ||=
  65. if (action = last_action)
  66. last_act_on_self = acts.last
  67. act_of_last_action = action.act
  68. return act_of_last_action unless last_act_on_self
  69. return last_act_on_self unless act_of_last_action
  70. return last_act_on_self if act_of_last_action == last_act_on_self
  71. if last_act_on_self.acted_at > act_of_last_action.acted_at
  72. last_act_on_self
  73. else
  74. act_of_last_action
  75. end
  76. end
  77. end
  78. 1 def previous_action action_id
  79. return unless action_id
  80. action_index = actions.find_index { |a| a.id == action_id }
  81. all_actions[action_index - 1] if action_index.to_i.nonzero?
  82. end
  83. 1 private
  84. 1 def extract_action_id action_arg
  85. 1 action_arg.is_a?(Card::Action) ? action_arg.id : action_arg
  86. end
  87. end;end;end;end;end;
  88. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-history/set/all/history/last.rb ~~

card/tmpsets/set/mod018-card-mod-history/all/history/revision.rb

40.0% lines covered

40 relevant lines. 16 lines covered and 24 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module History;
  3. # Set: All cards (History, Revision)
  4. #
  5. 1 module Revision;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-history/set/all/history/revision.rb"; end
  8. 1 def revision action, before_action=false
  9. # a "revision" refers to the state of all tracked fields
  10. # at the time of a given action
  11. action = Card::Action.fetch(action) if action.is_a? Integer
  12. return unless action
  13. if before_action
  14. revision_before_action action
  15. else
  16. revision_attributes action
  17. end
  18. end
  19. 1 def revision_attributes action
  20. Card::Change::TRACKED_FIELDS.each_with_object({}) do |field, attr_changes|
  21. last_change = action.change(field) || last_change_on(field, not_after: action)
  22. attr_changes[field.to_sym] = (last_change ? last_change.value : self[field])
  23. end
  24. end
  25. 1 def revision_before_action action
  26. if (prev_action = action.previous_action)
  27. revision prev_action
  28. else
  29. { trash: true }
  30. end
  31. end
  32. 1 def rollback_request?
  33. 58 history? && actions_to_revert.any?
  34. end
  35. 1 def process_revert_actions revert_actions=nil
  36. revert_actions ||= actions_to_revert
  37. update_args = { subcards: {} }
  38. reverting_to_previous = Env.params["revert_to"] == "previous"
  39. revert_actions.each do |action|
  40. merge_revert_action! action, update_args, reverting_to_previous
  41. end
  42. update_args
  43. end
  44. 1 def actions_to_revert
  45. 47 if (act_id = Env.params["revert_act"])
  46. Act.find(act_id).actions
  47. else
  48. 47 explicit_actions_to_revert
  49. end
  50. end
  51. 1 def explicit_actions_to_revert
  52. 47 Array.wrap(Env.params["revert_actions"]).map do |a_id|
  53. Action.fetch(a_id) || nil
  54. end.compact
  55. end
  56. 1 def merge_revert_action! action, update_args, reverting_to_previous
  57. rev = action.card.revision(action, reverting_to_previous)
  58. rev.delete :name unless rev[:name] # handles null name field in compound cards
  59. if action.card_id == id
  60. update_args.merge! rev
  61. else
  62. update_args[:subcards][action.card.name] = rev
  63. end
  64. end
  65. end;end;end;end;end;
  66. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-history/set/all/history/revision.rb ~~

card/tmpsets/set/mod018-card-mod-history/all/history/selected.rb

56.41% lines covered

39 relevant lines. 22 lines covered and 17 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module History;
  3. # Set: All cards (History, Selected)
  4. #
  5. # if these aren't in a nested module, the methods just overwrite the base
  6. # methods, but we need a distinct module so that super will be able to refer to
  7. 1 module Selected;
  8. 1 extend Card::Set
  9. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-history/set/all/history/selected.rb"; end
  10. # the base methods.
  11. 1 def content
  12. 2609 @selected_action_id ? selected_content : super
  13. end
  14. 1 def content= value
  15. 57 @selected_content = nil
  16. 57 super
  17. end
  18. 1 def select_action_by_params params
  19. 26 action = nth_action(params[:rev]) || action_from_id(params[:rev_id])
  20. 26 return unless action
  21. select_action action.id
  22. end
  23. 1 def select_action action_id
  24. run_callbacks :select_action do
  25. self.selected_action_id = action_id
  26. end
  27. end
  28. 1 def selected_action_id
  29. @selected_action_id || (@current_action&.id) || last_action_id
  30. end
  31. 1 def selected_action_id= action_id
  32. @selected_content = nil
  33. @selected_action_id = action_id
  34. end
  35. 1 def selected_action
  36. selected_action_id && Action.fetch(selected_action_id)
  37. end
  38. 1 def selected_content
  39. @selected_content ||= content_at_time_of_selected_action || db_content
  40. end
  41. 1 def content_at_time_of_selected_action
  42. lc = last_change_on(:db_content, not_after: @selected_action_id, including_drafts: true)
  43. lc&.value
  44. end
  45. 1 def with_selected_action_id action_id
  46. current_action_id = @selected_action_id
  47. select_action_id action_id
  48. result = yield
  49. select_action_id current_action_id
  50. result
  51. end
  52. 1 def select_action_id action_id
  53. run_callbacks :select_action do
  54. self.selected_action_id = action_id
  55. end
  56. end
  57. 1 def selected_content_action_id
  58. 159 @selected_action_id || new_content_action_id || last_content_action_id
  59. end
  60. end;end;end;end;end;
  61. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-history/set/all/history/selected.rb ~~

card/tmpsets/set/mod018-card-mod-history/all/history/views.rb

50.0% lines covered

22 relevant lines. 11 lines covered and 11 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module History;
  3. # Set: All cards (History, Views)
  4. #
  5. # History views
  6. 1 module Views;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-history/set/all/history/views.rb"; end
  9. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  10. 1 view :history, cache: :never do
  11. frame do
  12. class_up "d0-card-body", "history-slot"
  13. acts_layout card.history_acts, :relative, :show
  14. end
  15. end
  16. 1 view :act, cache: :never do
  17. act_listing act_from_context
  18. end
  19. 1 view :act_legend do
  20. bs_layout do
  21. row md: [12, 12], lg: [7, 5] do
  22. col action_legend
  23. col content_legend, class: "text-right"
  24. end
  25. end
  26. end
  27. 1 view :draft_legend do
  28. "#{action_icon(:draft)} unsaved draft"
  29. end
  30. 1 view :action_summary do
  31. action_content action_from_context, :summary
  32. end
  33. 1 view :action_expanded do
  34. action_content action_from_context, :expanded
  35. end
  36. end
  37. end;end;end;end;end;
  38. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-history/set/all/history/views.rb ~~

card/tmpsets/set/mod018-card-mod-history/all/history_bridge.rb

31.71% lines covered

41 relevant lines. 13 lines covered and 28 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (HistoryBridge)
  4. #
  5. 1 module HistoryBridge;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-history/set/all/history_bridge.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :creator_credit,
  10. wrap: { div: { class: "text-muted creator-credit" } }, cache: :never do
  11. return "" unless card.real?
  12. "Created by #{nest card.creator, view: :link} "\
  13. "#{time_ago_in_words(card.created_at)} ago"
  14. end
  15. 1 view :updated_by, wrap: { div: { class: "text-muted" } } do
  16. return "" unless card.id
  17. updaters = Card.search(updater_of: { id: card.id })
  18. return "" unless updaters.present?
  19. updaters = updater_links updaters, others_target: Card.fetch(card, :editors)
  20. "Updated by #{updaters}"
  21. end
  22. 1 def updater_links updaters, item_view: :link, max_count: 3, others_target: card
  23. return "" unless updaters.present?
  24. total = updaters.size
  25. fetch_count = total > max_count ? max_count - 1 : max_count
  26. reduced = first_card(fetch_count).map { |c| nest c, view: item_view }
  27. if total > max_count
  28. reduced << link_to_card(others_target, "#{total - fetch_count} others")
  29. end
  30. reduced.to_sentence
  31. end
  32. 1 def acts_bridge_layout acts, context=:bridge
  33. output [
  34. _render_creator_credit,
  35. act_link_list(acts, context),
  36. act_paging(acts, context)
  37. ]
  38. end
  39. 1 def act_link_list acts, context
  40. items = acts_for_accordion(acts, context) do |act, seq|
  41. act_link_list_item act, seq, context
  42. end
  43. bridge_pills items
  44. end
  45. 1 def act_link_list_item act, seq=nil, _context=nil
  46. opts = act_listing_opts_from_params(seq)
  47. opts[:slot_class] = "revision-#{act.id} history-slot nav-item"
  48. act_renderer(:bridge).new(self, act, opts).bridge_link
  49. end
  50. 1 def act_list_group acts, context, &block
  51. list_group acts_for_accordion(acts, context, &block), class: "clear-both"
  52. end
  53. 1 view :bridge_act, cache: :never do
  54. opts = act_listing_opts_from_params(nil)
  55. act = act_from_context
  56. ar = act_renderer(:bridge).new(self, act, opts)
  57. class_up "action-list", "my-3"
  58. wrap_with_overlay title: ar.overlay_title, slot: breadcrumb_data("History") do
  59. act_listing(act, opts[:act_seq], :bridge)
  60. end
  61. end
  62. end
  63. end;end;end;end;
  64. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-history/set/all/history_bridge.rb ~~

card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment.rb

67.19% lines covered

64 relevant lines. 43 lines covered and 21 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (Attachment)
  4. #
  5. 1 module Attachment;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/abstract/attachment.rb"; end
  8. 1 attr_writer :empty_ok
  9. 1 def self.included host_class
  10. 2 host_class.extend CarrierWave::CardMount
  11. end
  12. 1 event :select_file_revision, after: :select_action do
  13. attachment.retrieve_from_store!(attachment.identifier)
  14. end
  15. # we need a card id for the path so we have to update db_content when we have
  16. # an id
  17. 4 event :correct_identifier, :finalize, on: :create, when: proc { |c| !c.web? } do
  18. 3 update_column(:db_content, attachment.db_content)
  19. 3 expire
  20. end
  21. 1 event :save_original_filename, :prepare_to_store, on: :save, when: :file_ready_to_save? do
  22. 3 return unless @current_action
  23. 2 @current_action.update! comment: original_filename
  24. end
  25. 1 event :validate_file_exist, :validate, on: :create do
  26. 3 return if empty_ok?
  27. 3 if will_be_stored_as == :web
  28. errors.add "url is missing" if content.blank?
  29. 3 elsif !attachment.file.present?
  30. errors.add attachment_name, "is missing"
  31. end
  32. end
  33. 4 event :write_identifier, after: :save_original_filename, when: proc { |c| !c.web? } do
  34. 3 self.content = attachment.db_content
  35. end
  36. 1 def file_ready_to_save?
  37. 3 attachment.file.present? &&
  38. !preliminary_upload? &&
  39. !save_preliminary_upload? &&
  40. attachment_is_changing?
  41. end
  42. 1 def item_names _args={} # needed for flexmail attachments. hacky.
  43. [name]
  44. end
  45. 1 def original_filename
  46. 2 return content.split("/").last if web?
  47. 2 attachment.original_filename
  48. end
  49. 1 def unfilled?
  50. !attachment.present? && !save_preliminary_upload? && !subcards? && blank_content?
  51. end
  52. 1 def attachment_changed?
  53. send "#{attachment_name}_changed?"
  54. end
  55. 1 def attachment_is_changing?
  56. 3 send "#{attachment_name}_is_changing?"
  57. end
  58. 1 def attachment_before_act
  59. send "#{attachment_name}_before_act"
  60. end
  61. 1 def create_versions? _new_file
  62. true
  63. end
  64. 1 def empty_ok?
  65. 3 @empty_ok
  66. end
  67. 1 def assign_set_specific_attributes
  68. # reset content if we really have something to upload
  69. 199 self.content = nil if set_specific[attachment_name.to_s].present?
  70. 199 super
  71. end
  72. 1 def delete_files_for_action action
  73. with_selected_action_id(action.id) do
  74. attachment.file.delete
  75. attachment.versions.each_value do |version|
  76. version.file.delete
  77. end
  78. end
  79. end
  80. 1 def revision action, before_action=false
  81. return unless (result = super)
  82. result[:empty_ok] = true
  83. result
  84. end
  85. 1 def attachment_format ext
  86. 1 if ext.present? && attachment && (original_ext = attachment.extension.sub(/^\./, ""))
  87. 1 if ["file", original_ext].member? ext
  88. 1 original_ext
  89. elsif (exts = Mime::Types[attachment.content_type])
  90. if exts.find { |mt| mt.extensions.member? ext }
  91. ext
  92. else
  93. exts[0].extensions[0]
  94. end
  95. end
  96. end
  97. rescue => e
  98. Rails.logger.info "attachment_format issue: #{e.message}"
  99. nil
  100. end
  101. end;end;end;end;
  102. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/abstract/attachment.rb ~~

card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/cloud.rb

35.62% lines covered

73 relevant lines. 26 lines covered and 47 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Abstract; module Attachment;
  3. # Set: Abstract (Attachment, Cloud)
  4. #
  5. 1 module Cloud;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/abstract/attachment/cloud.rb"; end
  8. 1 event :change_bucket_if_read_only, :initialize,
  9. on: :update, when: :change_bucket_if_read_only? do
  10. @new_storage_type = storage_type_from_config
  11. end
  12. 1 event :validate_storage_type_update, :validate, on: :update, when: :cloud? do
  13. # FIXME: make it possible to retrieve the file from cloud storage
  14. # to store it somewhere else. Currently, it only works to change the
  15. # storage type if a new file is provided
  16. # i.e. `update storage_type: :local` fails but
  17. # `update storage_type: :local, file: [file handle]` is ok
  18. return unless storage_type_changed? && !attachment_is_changing?
  19. errors.add :storage_type, tr(:moving_files_is_not_supported)
  20. end
  21. 1 def bucket
  22. 76 @bucket ||= cloud? && (new_card_bucket || bucket_from_content || bucket_from_config)
  23. end
  24. 1 def new_card_bucket
  25. return unless new_card?
  26. # If the file is assigned before the bucket option we have to
  27. # check if there is a bucket options in set_specific.
  28. # That happens for exmaple when the file appears before the bucket in the
  29. # options hash:
  30. # Card.create file: file_handle, bucket: "my_bucket"
  31. set_specific[:bucket] || set_specific["bucket"] || bucket_from_config
  32. end
  33. 1 def bucket_config
  34. @bucket_config ||= load_bucket_config
  35. end
  36. 1 def load_bucket_config
  37. return {} unless bucket
  38. bucket_config = Cardio.config.file_buckets&.dig(bucket.to_sym) || {}
  39. bucket_config.symbolize_keys!
  40. bucket_config[:credentials]&.symbolize_keys!
  41. # we don't want :attributes hash symbolized, so we can't use
  42. # deep_symbolize_keys
  43. ensure_bucket_config do
  44. load_bucket_config_from_env bucket_config
  45. end
  46. end
  47. 1 def ensure_bucket_config
  48. yield.tap do |config|
  49. require_configuration! config
  50. require_credentials! config
  51. end
  52. end
  53. 1 def require_configuration! config
  54. cant_find_in_bucket! "configuration" unless config.present?
  55. end
  56. 1 def require_credentials! config
  57. cant_find_in_bucket! "credentials" unless config[:credentials]
  58. end
  59. 1 def cant_find_in_bucket! need
  60. raise Card::Error, "couldn't find #{need} for bucket #{bucket}"
  61. end
  62. 1 def load_bucket_config_from_env config
  63. config ||= {}
  64. each_config_option_from_env do |key|
  65. replace_with_env_variable config, key
  66. end
  67. credential_config config do |cred_hash|
  68. load_bucket_credentials_from_env cred_hash
  69. end
  70. end
  71. 1 def credential_config config
  72. config[:credentials] ||= {}
  73. yield config[:credentials]
  74. config.delete :credentials if config[:credentials].blank?
  75. config
  76. end
  77. 1 def each_config_option_from_env
  78. CarrierWave::FileCardUploader::CONFIG_OPTIONS.each do |key|
  79. yield key unless key.in? %i[attributes credentials]
  80. end
  81. end
  82. 1 def load_bucket_credentials_from_env cred_config
  83. each_credential_from_env do |option|
  84. replace_with_env_variable cred_config, option, "credentials"
  85. end
  86. end
  87. 1 def each_credential_from_env
  88. regexp = credential_from_env_regexp
  89. ENV.each_key do |env_key|
  90. next unless (m = regexp.match env_key)
  91. yield m[:option].downcase.to_sym
  92. end
  93. end
  94. 1 def credential_from_env_regexp
  95. Regexp.new "^(?:#{bucket.to_s.upcase}_)?CREDENTIALS_(?<option>.+)$"
  96. end
  97. 1 def replace_with_env_variable config, option, prefix=nil
  98. env_key = [prefix, option].compact.join("_").upcase
  99. new_value = ENV["#{bucket.to_s.upcase}_#{env_key}"] || ENV[env_key]
  100. config[option] = new_value if new_value
  101. end
  102. 1 def bucket_from_content
  103. return unless content
  104. content.match(/^\((?<bucket>[^)]+)\)/) { |m| m[:bucket] }
  105. end
  106. 1 def bucket_from_config
  107. cnf = Cardio.config
  108. cnf.file_default_bucket || cnf.file_buckets&.keys&.first
  109. end
  110. 1 def change_bucket_if_read_only?
  111. cloud? && bucket_config[:read_only] && attachment_is_changing?
  112. end
  113. 1 def bucket= value
  114. if @action == :update
  115. @new_bucket = value
  116. else
  117. @bucket = value
  118. end
  119. end
  120. end;end;end;end;end;
  121. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/abstract/attachment/cloud.rb ~~

card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/coded.rb

56.25% lines covered

16 relevant lines. 9 lines covered and 7 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Abstract; module Attachment;
  3. # Set: Abstract (Attachment, Coded)
  4. #
  5. 1 module Coded;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/abstract/attachment/coded.rb"; end
  8. 1 event :lose_coded_status_on_update, :initialize, on: :update, when: :coded? do
  9. # unless explicit
  10. return if @new_mod
  11. @new_storage_type ||= storage_type_from_config
  12. end
  13. 1 event :validate_coded_storage_type, :validate, on: :save, when: :will_become_coded? do
  14. errors.add :storage_type, tr(:mod_argument_needed_to_save) unless mod || @new_mod
  15. errors.add :storage_type, tr(:codename_needed_for_storage) if codename.blank?
  16. end
  17. 1 def will_become_coded?
  18. 14 will_be_stored_as == :coded
  19. end
  20. 1 def mod= value
  21. if @action == :update && mod != value
  22. @new_mod = value.to_s
  23. else
  24. @mod = value.to_s
  25. end
  26. end
  27. end;end;end;end;end;
  28. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/abstract/attachment/coded.rb ~~

card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/local.rb

96.43% lines covered

28 relevant lines. 27 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Abstract; module Attachment;
  3. # Set: Abstract (Attachment, Local)
  4. #
  5. 1 module Local;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/abstract/attachment/local.rb"; end
  8. 1 event :update_public_link_on_create, :integrate, on: :create, when: :local? do
  9. 3 update_public_link
  10. end
  11. 1 event :remove_public_link_on_delete, :integrate, on: :delete, when: :local? do
  12. remove_public_links
  13. end
  14. 1 event :update_public_link, after: :update_read_rule, when: :local? do
  15. 5 return if content.blank?
  16. 5 if who_can(:read).include? Card::AnyoneID
  17. 3 create_public_links
  18. else
  19. 2 remove_public_links
  20. end
  21. end
  22. 1 private
  23. 1 def create_public_links
  24. 3 path = attachment.public_path
  25. 3 return if File.exist? path
  26. 3 FileUtils.mkdir_p File.dirname(path)
  27. 3 File.symlink attachment.path, path unless File.symlink? path
  28. 3 create_versions_public_links
  29. end
  30. 1 def create_versions_public_links
  31. 3 attachment.versions.each_value do |version|
  32. 8 next if File.symlink? version.public_path
  33. 8 File.symlink version.path, version.public_path
  34. end
  35. end
  36. 1 def remove_public_links
  37. 2 symlink_dir = File.dirname attachment.public_path
  38. 2 return unless Dir.exist? symlink_dir
  39. 2 FileUtils.rm_rf symlink_dir
  40. end
  41. end;end;end;end;end;
  42. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/abstract/attachment/local.rb ~~

card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/paths.rb

91.43% lines covered

35 relevant lines. 32 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Abstract; module Attachment;
  3. # Set: Abstract (Attachment, Paths)
  4. #
  5. 1 module Paths;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/abstract/attachment/paths.rb"; end
  8. 1 MOD_FILE_DIR = "file".freeze
  9. 1 def store_dir
  10. 11 will_become_coded? ? coded_dir(@new_mod) : upload_dir
  11. end
  12. 1 def retrieve_dir
  13. 232 coded? ? coded_dir : upload_dir
  14. end
  15. # place for files of regular file cards
  16. 1 def upload_dir
  17. 34 id ? "#{files_base_dir}/#{id}" : tmp_upload_dir
  18. end
  19. # place for files of mod file cards
  20. 1 def coded_dir new_mod=nil
  21. 209 dir = File.join mod_dir(new_mod), MOD_FILE_DIR, codename.to_s
  22. 209 FileUtils.mkdir_p(dir) unless File.directory?(dir)
  23. 209 dir
  24. end
  25. 1 def mod_dir new_mod=nil
  26. 209 mod_name = new_mod || mod
  27. 209 dir = Mod.dirs.path(mod_name) || (mod_name.to_sym == :test && "test")
  28. 209 raise Error, "can't find mod \"#{mod_name}\"" unless dir
  29. 209 dir
  30. end
  31. 1 def files_base_dir
  32. 76 dir = bucket ? bucket_config[:subdirectory] : Card.paths["files"].existent.first
  33. 76 dir || files_base_dir_configuration_error
  34. end
  35. 1 def files_base_dir_configuration_error
  36. raise StandardError,
  37. "missing directory for file cache (default is `files` in deck root)"
  38. end
  39. # used in the indentifier
  40. 1 def file_dir
  41. 147 if coded?
  42. 116 ":#{codename}"
  43. 31 elsif cloud?
  44. "(#{bucket})/#{file_id}"
  45. else
  46. 31 "~#{file_id}"
  47. end
  48. end
  49. 1 def public?
  50. who_can(:read).include? Card::AnyoneID
  51. end
  52. 1 def file_id
  53. 31 id? ? id : upload_cache_card.id
  54. end
  55. end;end;end;end;end;
  56. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/abstract/attachment/paths.rb ~~

card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/storage_type.rb

64.89% lines covered

94 relevant lines. 61 lines covered and 33 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Abstract; module Attachment;
  3. # Set: Abstract (Attachment, StorageType)
  4. #
  5. 1 module StorageType;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/abstract/attachment/storage_type.rb"; end
  8. 1 attr_writer :bucket, :storage_type
  9. 1 event :storage_type_change, :store, on: :update, when: :storage_type_changed? do
  10. # carrierwave stores file if @cache_id is not nil
  11. attachment.cache_stored_file!
  12. # attachment.retrieve_from_cache!(attachment.cache_name)
  13. update_storage_attributes
  14. # next line might be necessary to move files to cloud
  15. # make sure that we get the new identifier
  16. # otherwise action_id will return wrong id for new identifier
  17. db_content_will_change!
  18. write_identifier
  19. end
  20. 1 event :validate_storage_type, :validate, on: :save do
  21. 3 unless known_storage_type? will_be_stored_as
  22. errors.add :storage_type, tr(
  23. :unknown_storage_type,
  24. new_storage_type: @new_storage_type
  25. )
  26. end
  27. end
  28. 1 def will_be_stored_as
  29. 20 @new_storage_type || storage_type
  30. end
  31. 1 def read_only?
  32. web? || (cloud? && bucket_config[:read_only])
  33. end
  34. 1 def cloud?
  35. 249 storage_type == :cloud
  36. end
  37. 1 def web?
  38. 188 storage_type == :web
  39. end
  40. 1 def local?
  41. 6 storage_type == :local
  42. end
  43. 1 def coded?
  44. 891 storage_type == :coded
  45. end
  46. 1 def remote_storage?
  47. 1 cloud? || web?
  48. end
  49. 1 def storage_type
  50. 1597 @storage_type ||=
  51. 127 new_card? ? storage_type_from_config : storage_type_from_content
  52. end
  53. 1 def deprecated_mod_file?
  54. content && (lines = content.split("\n")) && lines.size == 4
  55. end
  56. 1 def mod
  57. 325 @mod ||= coded? && mod_from_content
  58. end
  59. 1 def mod_from_content
  60. 117 if content =~ %r{^:[^/]+/([^.]+)}
  61. 117 Regexp.last_match(1) # current mod_file format
  62. else
  63. mod_from_deprecated_content
  64. end
  65. end
  66. # old format is still used in card_changes
  67. 1 def mod_from_deprecated_content
  68. return if content =~ /^\~/
  69. return unless (lines = content.split("\n")) && lines.size == 4
  70. lines.last
  71. end
  72. 1 def storage_type_from_config
  73. 3 valid_storage_type ENV["FILE_STORAGE"] || Cardio.config.file_storage
  74. end
  75. 1 def valid_storage_type storage_type
  76. 3 storage_type.to_sym.tap do |type|
  77. 3 invalid_storage_type! type unless type.in? valid_storage_type_list
  78. end
  79. end
  80. 1 def valid_storage_type_list
  81. 3 CarrierWave::FileCardUploader::STORAGE_TYPES
  82. end
  83. 1 def invalid_storage_type! type
  84. raise Card::Error, tr(:error_invalid_storage_type, type: type)
  85. end
  86. 1 def storage_type_from_content
  87. 124 case content
  88. when /^\(/ then :cloud
  89. when %r{/^https?\:/} then :web
  90. 7 when /^~/ then :local
  91. 117 when /^\:/ then :coded
  92. else
  93. if deprecated_mod_file?
  94. :coded
  95. else
  96. storage_type_from_config
  97. end
  98. end
  99. end
  100. 1 def update_storage_attributes
  101. @mod = @new_mod if @new_mod
  102. @bucket = @new_bucket if @new_bucket
  103. @storage_type = @new_storage_type
  104. end
  105. 1 def storage_type_changed?
  106. @new_bucket || (@new_storage_type && @new_storage_type != storage_type) || @new_mod
  107. end
  108. 1 def storage_type= value
  109. known_storage_type? value
  110. if @action == :update #&& storage_type != value
  111. # we cant update the storage type directly here
  112. # if we do then the uploader doesn't find the file we want to update
  113. @new_storage_type = value
  114. else
  115. @storage_type = value
  116. end
  117. end
  118. 1 def with_storage_options opts={}
  119. 153 old_values = {}
  120. 153 validate_temporary_storage_type_change opts[:storage_type]
  121. 153 %i[storage_type mod bucket].each do |opt_name|
  122. 459 next unless opts[opt_name]
  123. old_values[opt_name] = instance_variable_get "@#{opt_name}"
  124. instance_variable_set "@#{opt_name}", opts[opt_name]
  125. @temp_storage_type = true
  126. end
  127. 153 yield
  128. ensure
  129. 153 @temp_storage_type = false
  130. 153 old_values.each do |key, val|
  131. instance_variable_set "@#{key}", val
  132. end
  133. end
  134. 1 def temporary_storage_type_change?
  135. 127 @temp_storage_type
  136. end
  137. 1 def validate_temporary_storage_type_change new_storage_type=nil
  138. 153 new_storage_type ||= @new_storage_type
  139. 153 return unless new_storage_type
  140. unless known_storage_type? new_storage_type
  141. raise Error, tr(:unknown_storage_type, new_storage_type: new_storage_type)
  142. end
  143. if new_storage_type == :coded && codename.blank?
  144. raise Error, "codename needed for storage type :coded"
  145. end
  146. end
  147. 1 def known_storage_type? type=storage_type
  148. 3 type.in? CarrierWave::FileCardUploader::STORAGE_TYPES
  149. end
  150. end;end;end;end;end;
  151. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/abstract/attachment/storage_type.rb ~~

card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/upload_cache.rb

46.94% lines covered

49 relevant lines. 23 lines covered and 26 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Abstract; module Attachment;
  3. # Set: Abstract (Attachment, UploadCache)
  4. #
  5. # action id of the cached upload
  6. 1 module UploadCache;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/abstract/attachment/upload_cache.rb"; end
  9. 1 attr_accessor :action_id_of_cached_upload
  10. 1 def actionable?
  11. 8 super || preliminary_upload?
  12. end
  13. 1 event :prepare_attachment, :prepare_to_validate, on: :save, when: :preliminary_upload? do
  14. save_original_filename # save original filename as comment in action
  15. write_identifier # set db_content
  16. # (needs original filename to determine extension)
  17. store_attachment!
  18. store_card_changes
  19. # finalize_action # create Card::Change entry for db_content
  20. card_id = new_card? ? upload_cache_card.id : id
  21. @current_action.update! draft: true, card_id: card_id
  22. success << {
  23. target: (new_card? ? upload_cache_card : self),
  24. type: type_name,
  25. view: "preview_editor",
  26. rev_id: current_action.id
  27. }
  28. abort :success
  29. end
  30. 1 event :assign_attachment_on_create, :initialize,
  31. after: :assign_action, on: :create, when: :save_preliminary_upload? do
  32. return unless (action = Card::Action.fetch(@action_id_of_cached_upload))
  33. upload_cache_card.selected_action_id = action.id
  34. upload_cache_card.select_file_revision
  35. assign_attachment upload_cache_card.attachment.file, action.comment
  36. end
  37. 1 event :assign_attachment_on_update, :initialize,
  38. after: :assign_action, on: :update, when: :save_preliminary_upload? do
  39. return unless (action = Card::Action.fetch(@action_id_of_cached_upload))
  40. uploaded_file = with_selected_action_id(action.id) { attachment.file }
  41. assign_attachment uploaded_file, action.comment
  42. end
  43. 1 def assign_attachment file, original_filename
  44. send "#{attachment_name}=", file
  45. write_identifier
  46. @current_action&.update! comment: original_filename
  47. end
  48. 1 event :delete_cached_upload_file_on_create, :integrate,
  49. on: :create, when: :save_preliminary_upload? do
  50. return unless (action = Card::Action.fetch(@action_id_of_cached_upload))
  51. upload_cache_card.delete_files_for_action action
  52. action.delete
  53. end
  54. # at some point uploaded files of canceled file card creation
  55. # should be deleted. We do this when ever an new file is created.
  56. 1 event :clear_draft_files, :integrate_with_delay, priority: 100, on: :create do
  57. 3 Card.delete_tmp_files_of_cached_uploads
  58. end
  59. 1 event :delete_cached_upload_file_on_update, :integrate,
  60. on: :update, when: :save_preliminary_upload? do
  61. return unless (action = Card::Action.fetch(@action_id_of_cached_upload))
  62. delete_files_for_action action
  63. action.delete
  64. end
  65. # used for uploads for new cards until the new card is created
  66. 1 def upload_cache_card
  67. 2 cache_card_codename = "new_#{attachment_name}"
  68. 2 @upload_cache_card ||= Card::Codename.card(cache_card_codename) { Card[:new_file] }
  69. end
  70. 1 def preliminary_upload?
  71. 10 Card::Env && Card::Env.params[:attachment_upload]
  72. end
  73. 1 def save_preliminary_upload?
  74. 8 @action_id_of_cached_upload.present?
  75. end
  76. # place for files if card doesn't have an id yet
  77. 1 def tmp_upload_dir _action_id=nil
  78. "#{files_base_dir}/#{upload_cache_card.id}"
  79. end
  80. end;end;end;end;end;
  81. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/abstract/attachment/upload_cache.rb ~~

card/tmpsets/set/mod019-card-mod-carrierwave/abstract/attachment/web.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Abstract; module Attachment;
  3. # Set: Abstract (Attachment, Web)
  4. #
  5. 1 module Web;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/abstract/attachment/web.rb"; end
  8. 1 def no_upload?
  9. web? || storage_type_from_config == :web
  10. end
  11. end;end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/abstract/attachment/web.rb ~~

card/tmpsets/set/mod019-card-mod-carrierwave/all/file_utils.rb

63.64% lines covered

22 relevant lines. 14 lines covered and 8 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (FileUtils)
  4. #
  5. 1 module FileUtils;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/all/file_utils.rb"; end
  8. 1 module ClassMethods
  9. 1 def update_all_storage_locations
  10. Card.search(type_id: ["in", Card::FileID, Card::ImageID])
  11. .each(&:update_storage_location!)
  12. end
  13. 1 def delete_tmp_files_of_cached_uploads
  14. 3 cards_with_disposable_attachments do |card, action|
  15. card.delete_files_for_action action
  16. action.delete
  17. end
  18. end
  19. 1 def cards_with_disposable_attachments
  20. 3 draft_actions_with_attachment.each do |action|
  21. # we don't want to delete uploads in progress
  22. next unless old_enough?(action.created_at) && (card = action.card)
  23. # we can't delete attachments we don't have write access to
  24. next if card.read_only?
  25. yield card, action
  26. end
  27. end
  28. 1 def old_enough? time, expiration_time=5.day.to_i
  29. Time.now - time > expiration_time
  30. end
  31. 1 def draft_actions_with_attachment
  32. 3 Card::Action.find_by_sql(
  33. "SELECT * FROM card_actions "\
  34. "INNER JOIN cards ON card_actions.card_id = cards.id "\
  35. "WHERE cards.type_id IN (#{Card::FileID}, #{Card::ImageID}) "\
  36. "AND card_actions.draft = true"
  37. )
  38. end
  39. 1 def count_cards_with_attachment
  40. Card.search type_id: ["in", Card::FileID, Card::ImageID], return: :count
  41. end
  42. end
  43. end;end;end;end;
  44. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/all/file_utils.rb ~~

card/tmpsets/set/mod019-card-mod-carrierwave/self/admin.rb

60.0% lines covered

10 relevant lines. 6 lines covered and 4 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Admin"
  4. #
  5. 1 module Admin;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/self/admin.rb"; end
  8. 1 add_to_basket(
  9. :tasks,
  10. name: :update_file_storage_locations,
  11. execute_policy: -> { Card.update_all_storage_locations },
  12. stats: {
  13. title: "cards with attachment",
  14. count: -> { Card.count_cards_with_attachment }
  15. # link_text: "update storage locations",
  16. # task: "update_file_storage_locations"
  17. }
  18. )
  19. 1 add_to_basket(
  20. :tasks,
  21. name: :delete_upload_tmp_files,
  22. execute_policy: -> { Card.delete_tmp_files_of_cached_uploads },
  23. stats: {
  24. title: "tmp files of canceled uploads",
  25. count: -> { ::Card.draft_actions_with_attachment },
  26. link_text: "delete tmp files",
  27. task: "delete_tmp_files_of_cached_uploads"
  28. }
  29. )
  30. end;end;end;end;
  31. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/self/admin.rb ~~

card/tmpsets/set/mod019-card-mod-carrierwave/self/favicon.rb

92.31% lines covered

13 relevant lines. 12 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Favicon"
  4. #
  5. 1 module Favicon;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/self/favicon.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :source do
  10. 23 source = card.type_id == Card::ImageID ? super() : nil
  11. 23 source.present? ? source : nest(:logo, view: :source, size: voo.size)
  12. end
  13. 1 view :link_tag, perms: :none do
  14. 23 return unless (source = render :source, size: :small)
  15. 23 tag :link, rel: "shortcut icon", href: source
  16. end
  17. 1 def raw_help_text
  18. "A favicon (or shortcut icon) is a small image used by browsers to help identify "\
  19. "your website. [[http://www.decko.org/favicon|How to customize your favicon]]"
  20. end
  21. end
  22. end;end;end;end;
  23. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/self/favicon.rb ~~

card/tmpsets/set/mod019-card-mod-carrierwave/self/new_file.rb

72.73% lines covered

11 relevant lines. 8 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "NewFile"
  4. #
  5. 1 module NewFile;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/self/new_file.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :source, cache: :never do
  10. super()
  11. end
  12. 1 view :core, cache: :never do
  13. super()
  14. end
  15. 1 view :input, cache: :never do
  16. super()
  17. end
  18. end
  19. end;end;end;end;
  20. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/self/new_file.rb ~~

card/tmpsets/set/mod019-card-mod-carrierwave/self/new_image.rb

72.73% lines covered

11 relevant lines. 8 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "NewImage"
  4. #
  5. 1 module NewImage;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/self/new_image.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :source, cache: :never do
  10. super()
  11. end
  12. 1 view :core, cache: :never do
  13. super()
  14. end
  15. 1 view :input, cache: :never do
  16. super()
  17. end
  18. end
  19. end;end;end;end;
  20. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/self/new_image.rb ~~

card/tmpsets/set/mod019-card-mod-carrierwave/type/file.rb

77.27% lines covered

66 relevant lines. 51 lines covered and 15 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "File" cards
  4. #
  5. 1 module File;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/type/file.rb"; end
  8. 1 attachment :file, uploader: CarrierWave::FileCardUploader
  9. 1 module SelectedAction
  10. 1 def select_action_by_params params
  11. # skip action table lookups for current revision
  12. 7 rev_id = params[:rev_id]
  13. 7 super unless rev_id && rev_id == last_content_action_id
  14. end
  15. 1 def last_content_action_id
  16. 127 return super if temporary_storage_type_change?
  17. # find action id from content (saves lookups)
  18. 127 db_content.to_s.split(%r{[/\.]})[-2]
  19. end
  20. end
  21. 1 include SelectedAction
  22. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  23. 1 view :source do
  24. 1 file = card.attachment
  25. 1 return "" unless file.valid?
  26. 1 contextualize_path file.url
  27. end
  28. 1 view :core do
  29. 1 handle_source do |source|
  30. 1 card_url source
  31. end
  32. end
  33. 1 def short_content
  34. number_to_human_size card.attachment.size
  35. end
  36. 1 def handle_source
  37. 3 source = _render_source
  38. 3 return "" if source.blank?
  39. 3 block_given? ? yield(source) : source
  40. rescue => e
  41. Rails.logger.info "Error with file source: #{e.message}"
  42. tr :file_error
  43. end
  44. 1 def selected_version
  45. 1 card.attachment
  46. end
  47. end
  48. 2 module FileFormat; module_parent.send :register_set_format, Card::Format::FileFormat, self; extend Card::Set::AbstractFormat
  49. # NOCACHE because returns send_file args. not in love with this...
  50. 1 view :core, cache: :never do
  51. # this means we only support known formats. dislike.
  52. 1 attachment_format = card.attachment_format(params[:format])
  53. 1 return _render_not_found unless attachment_format
  54. 1 return card.format(:html).render_core if card.remote_storage?
  55. 1 set_response_headers
  56. 1 args_for_send_file
  57. end
  58. 1 def args_for_send_file
  59. 1 file = selected_version
  60. 1 [file.path, { type: file.content_type,
  61. filename: "#{card.name.safe_key}#{file.extension}",
  62. x_sendfile: true,
  63. 1 disposition: (params[:format] == "file" ? "attachment" : "inline") }]
  64. end
  65. 1 def set_response_headers
  66. 1 return unless params[:explicit_file] && (response = controller&.response)
  67. 1 response.headers["Expires"] = 1.year.from_now.httpdate
  68. # currently using default "private", because proxy servers could block
  69. # needed permission checks
  70. # r.headers["Cache-Control"] = "public"
  71. end
  72. end
  73. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  74. 1 view :core do
  75. handle_source do |source|
  76. "<a href=\"#{source}\">#{tr :download, title: title_in_context(voo.title)}</a>"
  77. end
  78. end
  79. 1 view :input do
  80. if card.no_upload?
  81. text_field :content, class: "d0-card-content"
  82. else
  83. haml :file_chooser, action_text: file_chooser_action_text
  84. end
  85. end
  86. 1 view :preview_editor, unknown: true, cache: :never do
  87. haml :preview_editor
  88. end
  89. 1 def file_chooser_action_text
  90. action = card.new_card? ? "Add" : "Replace"
  91. "#{action} #{humanized_attachment_name}..."
  92. end
  93. 1 def humanized_attachment_name
  94. card.attachment_name.to_s.humanize
  95. end
  96. 1 def preview
  97. ""
  98. end
  99. 1 def cached_upload_card_name
  100. Card::Env.params[:attachment_upload].gsub(/\[\w+\]$/, "[action_id_of_cached_upload]")
  101. end
  102. 1 def preview_editor_delete_text
  103. tr :delete
  104. end
  105. end
  106. end;end;end;end;
  107. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/type/file.rb ~~

card/tmpsets/set/mod019-card-mod-carrierwave/type/image.rb

71.67% lines covered

60 relevant lines. 43 lines covered and 17 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Image" cards
  4. #
  5. 1 module Image;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/type/image.rb"; end
  8. 1 attachment :image, uploader: CarrierWave::ImageCardUploader
  9. 1 include File::SelectedAction
  10. 1 def create_versions? new_file
  11. 256 new_file.extension != "svg"
  12. end
  13. 1 def svg?
  14. 25 image&.extension == ".svg"
  15. end
  16. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  17. 1 include File::Format
  18. 1 view :one_line_content do
  19. _render_core size: :icon
  20. end
  21. 1 def short_content
  22. 2 render_core size: :icon
  23. end
  24. 1 view :source do
  25. 25 return card.content if card.web?
  26. 25 image = selected_version
  27. 25 return "" unless image.valid?
  28. 25 contextualize_path image.url
  29. end
  30. 1 def selected_version
  31. 25 size = determine_image_size
  32. 25 if size && size != :original
  33. 25 card.image.versions[size]
  34. else
  35. card.image
  36. end
  37. end
  38. 1 def handle_source
  39. 2 super
  40. end
  41. 1 def closed_size
  42. :icon
  43. end
  44. 1 def main_size
  45. :large
  46. end
  47. 1 def default_size
  48. :medium
  49. end
  50. 1 def determine_image_size
  51. 25 voo.size =
  52. case
  53. when nest_mode == :closed then closed_size
  54. 25 when voo.size.present? then voo.size.to_sym
  55. when main? then main_size
  56. else default_size
  57. end
  58. 25 voo.size = :original if voo.size == :full
  59. 25 voo.size
  60. end
  61. 1 view :inline do
  62. _render_core
  63. end
  64. end
  65. 2 module EmailHtmlFormat; module_parent.send :register_set_format, Card::Format::EmailHtmlFormat, self; extend Card::Set::AbstractFormat
  66. 1 view :inline, cache: :never do
  67. handle_source do |source|
  68. return source unless (mail = inherit :active_mail) &&
  69. ::File.exist?(path = selected_version.path)
  70. url = attach_image mail, path
  71. image_tag url
  72. end
  73. end
  74. 1 def attach_image mail, path
  75. mail.attachments.inline[path] = ::File.read path
  76. mail.attachments[path].url
  77. end
  78. end
  79. 2 module CssFormat; module_parent.send :register_set_format, Card::Format::CssFormat, self; extend Card::Set::AbstractFormat
  80. 1 view :core do
  81. handle_source
  82. end
  83. 1 view :content do # why is this necessary?
  84. render_core
  85. end
  86. end
  87. 2 module FileFormat; module_parent.send :register_set_format, Card::Format::FileFormat, self; extend Card::Set::AbstractFormat
  88. 1 include File::FileFormat
  89. end
  90. end;end;end;end;
  91. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/type/image.rb ~~

card/tmpsets/set/mod019-card-mod-carrierwave/type/image/html_views.rb

56.41% lines covered

39 relevant lines. 22 lines covered and 17 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Type; module Image;
  3. # Set: All "Image+HtmlViews" cards (HtmlViews)
  4. #
  5. 1 module HtmlViews;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/type/image/html_views.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 include File::HtmlFormat
  10. # core HTML image view.
  11. 1 view :core do
  12. 25 return card.attachment.read if card.svg?
  13. 2 with_valid_source do |source|
  14. 2 image_tag source, alt: card.name
  15. end
  16. end
  17. 1 def with_valid_source
  18. 2 handle_source do |source|
  19. 2 if source.blank? || source == "missing"
  20. # FIXME: these images should be "broken", not "missing"
  21. invalid_image source
  22. else
  23. 2 yield source
  24. # consider title..
  25. end
  26. end
  27. end
  28. 1 view :full_width do
  29. with_valid_source do |source|
  30. image_tag source, alt: card.name, class: "w-100"
  31. end
  32. end
  33. 1 def invalid_image source
  34. # ("missing" is the view for "unknown" now, so we shouldn't further confuse things)
  35. "<!-- invalid image for #{safe_name}; source: #{source} -->"
  36. end
  37. 1 def preview
  38. return if card.new_card? && !card.preliminary_upload?
  39. wrap_with :div, class: "attachment-preview",
  40. id: "#{card.attachment.filename}-preview" do
  41. _render_core size: :medium
  42. end
  43. end
  44. 1 def show_action_content_toggle? _action, _view_type
  45. true
  46. end
  47. 1 view :content_changes do
  48. content_changes card.last_action, :expanded
  49. end
  50. 1 def content_changes action, diff_type, hide_diff=false
  51. voo.size = diff_type == :summary ? :icon : :medium
  52. [old_image(action, hide_diff), new_image(action)].compact.join
  53. end
  54. 1 def old_image action, hide_diff
  55. return if hide_diff || !action
  56. return unless (last_change = card.last_change_on(:db_content, before: action))
  57. card.with_selected_action_id last_change.card_action_id do
  58. Card::Content::Diff.render_deleted_chunk _render_core
  59. end
  60. end
  61. 1 def new_image action
  62. card.with_selected_action_id action.id do
  63. Card::Content::Diff.render_added_chunk _render_core
  64. end
  65. end
  66. end
  67. end;end;end;end;end;
  68. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-carrierwave/set/type/image/html_views.rb ~~

card/tmpsets/set/mod020-card-mod-date/all/calendar.rb

100.0% lines covered

8 relevant lines. 8 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Calendar)
  4. #
  5. 1 module Calendar;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-date/set/all/calendar.rb"; end
  8. 1 Self::InputOptions.add_to_basket :options, "calendar"
  9. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  10. 1 def calendar_input
  11. 1 text_field :content, class: "date-editor datetimepicker-input",
  12. "data-toggle": "datetimepicker",
  13. "data-target": "##{form_prefix}_content.date-editor"
  14. end
  15. end
  16. end;end;end;end;
  17. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-date/set/all/calendar.rb ~~

card/tmpsets/set/mod020-card-mod-date/self/datepicker.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Datepicker"
  4. #
  5. 1 module Datepicker;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-date/set/self/datepicker.rb"; end
  8. 1 def raw_help_text
  9. <<-TEXT
  10. Configure the date select tool using these available
  11. [[https://tempusdominus.github.io/bootstrap-4/Options/|options]]
  12. TEXT
  13. end
  14. end;end;end;end;
  15. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-date/set/self/datepicker.rb ~~

card/tmpsets/set/mod020-card-mod-date/self/script_datepicker.rb

87.5% lines covered

8 relevant lines. 7 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ScriptDatepicker"
  4. #
  5. 1 module ScriptDatepicker;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-date/set/self/script_datepicker.rb"; end
  8. 1 include_set Abstract::VendorCodeFile
  9. 1 Self::ScriptMods.add_item :script_datepicker
  10. 1 def source_files
  11. %w[moment/min/moment-with-locales.min.js
  12. tempusdominus/build/js/tempusdominus-bootstrap-4.js]
  13. end
  14. end;end;end;end;
  15. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-date/set/self/script_datepicker.rb ~~

card/tmpsets/set/mod020-card-mod-date/self/script_datepicker_config.rb

100.0% lines covered

7 relevant lines. 7 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ScriptDatepickerConfig"
  4. #
  5. 1 module ScriptDatepickerConfig;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-date/set/self/script_datepicker_config.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 Self::ScriptEditors.add_item :script_datepicker_config
  10. 1 All::Head::HtmlFormat.add_to_basket :mod_js_config, [:datepicker, "setDatepickerConfig"]
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-date/set/self/script_datepicker_config.rb ~~

card/tmpsets/set/mod020-card-mod-date/self/style_datepicker.rb

100.0% lines covered

10 relevant lines. 10 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "StyleDatepicker"
  4. #
  5. 1 module StyleDatepicker;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-date/set/self/style_datepicker.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 Self::StyleLibraries.add_item :style_datepicker
  10. 1 def source_files
  11. 2 %w[lib/stylesheets/tempusdominus.scss
  12. vendor/tempusdominus/src/sass/_tempusdominus-bootstrap-4.scss]
  13. end
  14. 1 def source_dir
  15. 4 ""
  16. end
  17. end;end;end;end;
  18. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-date/set/self/style_datepicker.rb ~~

card/tmpsets/set/mod020-card-mod-date/type/date.rb

100.0% lines covered

7 relevant lines. 7 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Date" cards
  4. #
  5. 1 module Date;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-date/set/type/date.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def input_type
  10. 1 :calendar
  11. end
  12. end
  13. end;end;end;end;
  14. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-date/set/type/date.rb ~~

card/tmpsets/set/mod022-card-mod-follow/abstract/follow_option.rb

93.1% lines covered

29 relevant lines. 27 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Abstract
  3. # Set: Abstract (FollowOption)
  4. #
  5. 1 module FollowOption;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/abstract/follow_option.rb"; end
  8. 1 def restrictive_option?
  9. Card::FollowOption.restrictive_options.include? codename
  10. end
  11. 1 def description set_card
  12. 4 set_card.follow_label
  13. end
  14. # follow option methods on the Card class
  15. # FIXME: there's not a great reason to have these on the Card class
  16. 1 module ClassMethods
  17. # args:
  18. # position: <Fixnum> (starting at 1, default: add to end)
  19. 1 def restrictive_follow_opts args
  20. 2 add_option args, :restrictive
  21. end
  22. # args:
  23. # position: <Fixnum> (starting at 1, default: add to end)
  24. 1 def follow_opts args
  25. 2 add_option args, :main
  26. end
  27. 1 def follow_test opts={}, &block
  28. 2 Card::FollowOption.test[get_codename(opts)] = block
  29. end
  30. 1 def follower_candidate_ids opts={}, &block
  31. 2 Card::FollowOption.follower_candidate_ids[get_codename(opts)] = block
  32. end
  33. 1 private
  34. 1 def insert_option pos, item, type
  35. 4 list = Card::FollowOption.codenames(type)
  36. 4 list[pos] ? list.insert(pos, item) : (list[pos] = item)
  37. # If pos > codenames.size in a previous insert then we have a bunch
  38. # of preceding nils in the array.
  39. # Hence, we have to overwrite a nil value if we encounter one and
  40. # can't use insert.
  41. end
  42. 1 def add_option opts, type, &_block
  43. 4 codename = get_codename opts
  44. 4 if opts[:position]
  45. 4 insert_option opts[:position] - 1, codename, type
  46. else
  47. Card::FollowOption.codenames(type) << codename
  48. end
  49. 4 Card::FollowOption.codenames(:all) << codename
  50. end
  51. 1 def get_codename opts
  52. 8 opts[:codename] || name.match(/::(\w+)$/)[1].underscore.to_sym
  53. end
  54. end
  55. end;end;end;end;
  56. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/abstract/follow_option.rb ~~

card/tmpsets/set/mod022-card-mod-follow/all/follow.rb

65.0% lines covered

20 relevant lines. 13 lines covered and 7 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Follow)
  4. #
  5. # for override
  6. 1 module Follow;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/all/follow.rb"; end
  9. 1 def followable?
  10. 14 true
  11. end
  12. 1 def follow_label
  13. name
  14. end
  15. 1 def list_direct_followers?
  16. false
  17. end
  18. 1 def follow_option?
  19. codename && FollowOption.codenames.include?(codename)
  20. end
  21. # the set card to be followed if you want to follow changes of card
  22. 1 def follow_set_card
  23. Card.fetch name, :self
  24. end
  25. 1 def follow_rule_name user=nil
  26. follow_set_card&.follow_rule_name user
  27. end
  28. 1 def follow_rule_card user=nil, args={}
  29. Card.fetch follow_rule_name(user), args
  30. end
  31. 1 def follow_rule? user=nil
  32. Card.exists? follow_rule_name(user)
  33. end
  34. end;end;end;end;
  35. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/all/follow.rb ~~

card/tmpsets/set/mod022-card-mod-follow/all/follow/follow_link.rb

50.0% lines covered

30 relevant lines. 15 lines covered and 15 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Follow)
  4. #
  5. #! no set module
  6. 1 module Follow;
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/all/follow/follow_link.rb"; end
  8. 1 class FollowLink
  9. 1 attr_reader :format, :rule_content, :link_text, :action, :css_class, :hover_text
  10. 1 delegate :link_to, to: :format
  11. 1 def initialize format
  12. @format = format
  13. @card = format.card
  14. end
  15. 1 def modal_link icon=false
  16. opts = link_opts.merge(
  17. "data-path": link_opts[:path],
  18. "data-toggle": "modal",
  19. "data-target": "#modal-#{card.name.safe_key}",
  20. class: css_classes("follow-link", link_opts[:class])
  21. )
  22. link_to render_link_text(icon), opts
  23. end
  24. 1 def button
  25. opts = link_opts(:follow_section).merge(
  26. remote: true,
  27. class: @format.css_classes("follow-link", link_opts[:class],
  28. "slotter btn btn-sm btn-primary")
  29. )
  30. opts["data-update-foreign-slot"] = ".d0-card-body > .card-slot.RIGHT-Xfollower.content-view"
  31. opts["data-hover-text"] = hover_text if hover_text
  32. link_to render_link_text, opts
  33. end
  34. 1 def link_opts success_view=:follow_status
  35. { title: title,
  36. path: path(success_view),
  37. class: css_class }
  38. end
  39. 1 def render_link_text icon=false
  40. verb = %(<span class="follow-verb">#{link_text}</span>)
  41. icon = icon ? icon_tag(:flag) : ""
  42. [icon, verb].compact.join.html_safe
  43. end
  44. 1 private
  45. 1 def mark
  46. @card.follow_set_card.follow_rule_name Auth.current.name
  47. end
  48. 1 def path view=:follow_status
  49. @format.path mark: mark,
  50. action: :update,
  51. success: { id: @card.name, view: view },
  52. card: { content: "[[#{rule_content}]]" }
  53. end
  54. 1 def title
  55. "#{action} emails about changes to #{@card.follow_label}"
  56. end
  57. end
  58. end;end;end;end;
  59. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/all/follow/follow_link.rb ~~

card/tmpsets/set/mod022-card-mod-follow/all/follow/follow_link_views.rb

73.68% lines covered

19 relevant lines. 14 lines covered and 5 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module Follow;
  3. # Set: All cards (Follow, FollowLinkViews)
  4. #
  5. 1 module FollowLinkViews;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/all/follow/follow_link_views.rb"; end
  8. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  9. 1 def follow_link_class
  10. card.followed? ? StopFollowLink : StartFollowLink
  11. end
  12. 1 def show_follow?
  13. 1 Auth.signed_in? && !card.new_card? && card.followable?
  14. end
  15. end
  16. 2 module JsonFormat; module_parent.send :register_set_format, Card::Format::JsonFormat, self; extend Card::Set::AbstractFormat
  17. 1 view :follow_status do
  18. follow_link_class.link_opts
  19. end
  20. end
  21. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  22. 1 def follow_button
  23. follow_link_class.new(self).button
  24. end
  25. 1 def follow_modal_link
  26. follow_link_class.new(self).modal_link
  27. end
  28. 1 view :follow_button, cache: :never do
  29. follow_button
  30. end
  31. end
  32. end;end;end;end;end;
  33. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/all/follow/follow_link_views.rb ~~

card/tmpsets/set/mod022-card-mod-follow/all/follow/followed_by.rb

71.05% lines covered

38 relevant lines. 27 lines covered and 11 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module Follow;
  3. # Set: All cards (Follow, FollowedBy)
  4. #
  5. # used by +:followers overwritten in type/set.rb and type/cardtype.rb
  6. 1 module FollowedBy;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/all/follow/followed_by.rb"; end
  9. 1 def followed?
  10. followed_by? Auth.current_id
  11. end
  12. # for sets and cardtypes it doesn't check whether the users is following the
  13. # card itself instead it checks whether he is following the complete set
  14. 1 def followed_by? user_id
  15. follow_rule_applies?(user_id) || left&.followed_by_as_field?(self, user_id)
  16. end
  17. 1 def followed_by_as_field? field, user_id
  18. followed_field?(field) && followed_by?(user_id)
  19. end
  20. # returns true if according to the follow_field_rule followers of self also
  21. # follow changes of field_card
  22. 1 def followed_field? field_card
  23. return unless (follow_field_rule = rule_card(:follow_fields))
  24. follow_field_rule.item_names(context: self).find do |item|
  25. case item.to_name.key
  26. when field_card.key then true
  27. when :nests.cardname.key then nested_card?(field_card)
  28. end
  29. end
  30. end
  31. 1 def nested_card? card
  32. nestee_ids.include? card.id
  33. end
  34. ## the following methods all handle _explicit_ (direct) follow rules (not fields)
  35. 1 def follow_rule_applies? follower_id
  36. !follow_rule_option(follower_id).nil?
  37. end
  38. 1 def follow_rule_option follower_id
  39. 62 all_follow_rule_options(follower_id).find do |option|
  40. 124 follow_rule_option_applies? follower_id, option
  41. end
  42. end
  43. 1 def all_follow_rule_options follower_id
  44. 62 follow_rule = preference :follow, follower_id
  45. 62 return [] unless follow_rule.present?
  46. 62 follow_rule.split("\n")
  47. end
  48. 1 def follow_rule_option_applies? follower_id, option
  49. 124 option_code = option.to_name.code
  50. 124 candidate_ids = follower_candidate_ids_for_option option_code
  51. 124 follow_rule_option_applies_to_candidates? follower_id, option_code, candidate_ids
  52. end
  53. 1 def follow_rule_option_applies_to_candidates? follower_id, option_code, candidate_ids
  54. 124 if (test = FollowOption.test[option_code])
  55. test.call follower_id, candidate_ids
  56. else
  57. 124 candidate_ids.include? follower_id
  58. end
  59. end
  60. 1 def follower_candidate_ids_for_option option_code
  61. 124 return [] unless (block = FollowOption.follower_candidate_ids[option_code])
  62. 124 block.call self
  63. end
  64. end;end;end;end;end;
  65. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/all/follow/followed_by.rb ~~

card/tmpsets/set/mod022-card-mod-follow/all/follow/follower_ids.rb

62.32% lines covered

69 relevant lines. 43 lines covered and 26 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module Follow;
  3. # Set: All cards (Follow, FollowerIds)
  4. #
  5. 1 module FollowerIds;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/all/follow/follower_ids.rb"; end
  8. 1 FOLLOWER_IDS_CACHE_KEY = "FOLLOWER_IDS".freeze
  9. 1 card_accessor :followers
  10. 1 event :cache_expired_for_type_change, :store, on: :update, changed: %i[type_id name] do
  11. 19 act_card&.schedule_preference_expiration
  12. # FIXME: expire (also?) after save
  13. 19 Card.follow_caches_expired
  14. end
  15. 1 def schedule_preference_expiration
  16. 19 @expire_preferences_scheduled = true
  17. end
  18. 1 def expire_preferences?
  19. 318 @expire_preferences_scheduled
  20. end
  21. 1 event :expire_preferences_cache, :finalize, when: :expire_preferences? do
  22. 14 Card::Rule.clear_preference_cache
  23. end
  24. # follow cache methods on Card class
  25. 1 module ClassMethods
  26. 1 def follow_caches_expired
  27. 28 Card.clear_follower_ids_cache
  28. 28 Card::Rule.clear_preference_cache
  29. end
  30. 1 def follower_ids_cache
  31. Card.cache.read(FOLLOWER_IDS_CACHE_KEY) || {}
  32. end
  33. 1 def write_follower_ids_cache hash
  34. Card.cache.write FOLLOWER_IDS_CACHE_KEY, hash
  35. end
  36. 1 def clear_follower_ids_cache
  37. 28 Card.cache.write FOLLOWER_IDS_CACHE_KEY, nil
  38. end
  39. end
  40. 1 def write_follower_ids_cache user_ids
  41. hash = Card.follower_ids_cache
  42. hash[id] = user_ids
  43. Card.write_follower_ids_cache hash
  44. end
  45. 1 def read_follower_ids_cache
  46. Card.follower_ids_cache[id]
  47. end
  48. 1 def follower_names
  49. followers.map(&:name)
  50. end
  51. 1 def followers
  52. follower_ids.map do |id|
  53. Card.fetch(id)
  54. end
  55. end
  56. 1 def follower_ids
  57. @follower_ids = read_follower_ids_cache || begin
  58. result = direct_follower_ids + indirect_follower_ids
  59. write_follower_ids_cache result
  60. result
  61. end
  62. end
  63. 1 def followers_count
  64. follower_ids.size
  65. end
  66. 1 def indirect_follower_ids
  67. result = ::Set.new
  68. left_card = left
  69. while left_card
  70. result += left_card.direct_follower_ids if left_card.followed_field? self
  71. left_card = left_card.left
  72. end
  73. result
  74. end
  75. # all users (cards) that "directly" follow this card
  76. # "direct" means there is a follow rule that applies explicitly to this card.
  77. # one can also "indirectly" follow cards by following parent cards or other
  78. # cards that nest this one.
  79. 1 def direct_followers
  80. direct_follower_ids.map do |id|
  81. Card.fetch(id)
  82. end
  83. end
  84. 1 def direct_follower_ids &block
  85. 31 ids = ::Set.new
  86. 31 set_names.each do |set_name|
  87. 153 direct_follower_ids_for_set setcard_from_name(set_name), ids, &block
  88. end
  89. 31 ids
  90. end
  91. 1 def setcard_from_name set_name
  92. 153 Card.fetch set_name, new: { type_id: SetID }
  93. end
  94. 1 def direct_follower_ids_for_set set_card, ids
  95. 153 set_card.all_user_ids_with_rule_for(:follow).each do |user_id|
  96. 62 next if ids.include?(user_id) || !(option = follow_rule_option user_id)
  97. yield user_id, set_card, option if block_given?
  98. ids << user_id
  99. end
  100. end
  101. 1 def each_direct_follower_id_with_reason
  102. 31 direct_follower_ids do |user_id, set_card, follow_option|
  103. reason = follow_option.gsub(/[\[\]]/, "")
  104. yield user_id, set_card: set_card, option: reason
  105. end
  106. end
  107. end;end;end;end;end;
  108. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/all/follow/follower_ids.rb ~~

card/tmpsets/set/mod022-card-mod-follow/all/follow/start_follow_link.rb

50.0% lines covered

10 relevant lines. 5 lines covered and 5 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Follow)
  4. #
  5. #! no set module
  6. 1 module Follow;
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/all/follow/start_follow_link.rb"; end
  8. 1 class StartFollowLink < FollowLink
  9. 1 def initialize format
  10. @rule_content = "*always"
  11. @link_text = "follow"
  12. @action = "send"
  13. @css_class = ""
  14. super
  15. end
  16. end
  17. end;end;end;end;
  18. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/all/follow/start_follow_link.rb ~~

card/tmpsets/set/mod022-card-mod-follow/all/follow/stop_follow_link.rb

45.45% lines covered

11 relevant lines. 5 lines covered and 6 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Follow)
  4. #
  5. #! no set module
  6. 1 module Follow;
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/all/follow/stop_follow_link.rb"; end
  8. 1 class StopFollowLink < FollowLink
  9. 1 def initialize format
  10. @rule_content = "*never"
  11. @link_text = "following"
  12. @hover_text = "unfollow"
  13. @action = "stop sending"
  14. @css_class = "btn-item-delete"
  15. super
  16. end
  17. end
  18. end;end;end;end;
  19. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/all/follow/stop_follow_link.rb ~~

card/tmpsets/set/mod022-card-mod-follow/all/notify.rb

90.91% lines covered

44 relevant lines. 40 lines covered and 4 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Notify)
  4. #
  5. 1 module Notify;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/all/notify.rb"; end
  8. 1 attr_accessor :follower_stash
  9. 1 mattr_accessor :force_notifications
  10. 1 event :silence_notifications, :initialize, when: :silence_notifications? do
  11. 295 @silent_change = true
  12. end
  13. 1 def silence_notifications?
  14. 332 !(Card::Env[:controller] || force_notifications)
  15. end
  16. 1 event :notify_followers_after_save,
  17. :integrate_with_delay, on: :save, when: :notable_change? do
  18. 9 notify_followers
  19. end
  20. # in the delete case we have to calculate the follower_stash beforehand
  21. # but we can't pass the follower_stash through the ActiveJob queue.
  22. # We have to deal with the notifications in the integrate phase instead of the
  23. # integrate_with_delay phase
  24. 1 event :stash_followers, :store, on: :delete, when: :notable_change? do
  25. 2 act_card.follower_stash ||= FollowerStash.new
  26. 2 act_card.follower_stash.check_card self
  27. end
  28. 1 event :notify_followers_after_delete, :integrate, on: :delete, when: :notable_change? do
  29. 2 notify_followers
  30. end
  31. 1 def notify_followers
  32. 11 return unless (act = Card::Director.act)
  33. 11 act.reload
  34. 11 notify_followers_of act
  35. end
  36. 1 def notable_change?
  37. 390 !silent_change? && current_act_card? &&
  38. 15 (Card::Auth.current_id != WagnBotID) && followable?
  39. end
  40. 1 def silent_change?
  41. 421 silent_change
  42. end
  43. 1 private
  44. 1 def notify_followers_of act
  45. 11 act_followers(act).each_follower_with_reason do |follower, reason|
  46. next if !follower.account || (follower == act.actor)
  47. notify_follower follower, act, reason
  48. end
  49. end
  50. 1 def notify_follower follower, act, reason
  51. follower.account.send_change_notice act, reason[:set_card].name, reason[:option]
  52. end
  53. 1 def act_followers act
  54. 11 @follower_stash ||= FollowerStash.new
  55. 11 act.actions(false).each do |a|
  56. 31 next if !a.card || a.card.silent_change?
  57. 31 @follower_stash.check_card a.card
  58. end
  59. 11 @follower_stash
  60. end
  61. 1 def silent_change
  62. @silent_change || @supercard&.silent_change
  63. end
  64. 1 def current_act_card?
  65. 55 return false unless act_card
  66. 55 act_card.id.nil? || act_card.id == id
  67. # FIXME: currently card_id is nil for deleted acts (at least
  68. # in the store phase when it's tested). The nil test was needed
  69. # to make this work.
  70. end
  71. end;end;end;end;
  72. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/all/notify.rb ~~

card/tmpsets/set/mod022-card-mod-follow/all/notify/base_views.rb

80.28% lines covered

71 relevant lines. 57 lines covered and 14 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module Notify;
  3. # Set: All cards (Notify, BaseViews)
  4. #
  5. 1 module BaseViews;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/all/notify/base_views.rb"; end
  8. 2 module Format; module_parent.send :register_set_format, Card::Format, self; extend Card::Set::AbstractFormat
  9. 1 view :list_of_changes, denial: :blank, cache: :never do
  10. 4 action = notification_action voo.action_id
  11. 4 relevant_fields(action).map do |type|
  12. 8 edit_info_for(type, action)
  13. end.compact.join
  14. end
  15. 1 view :subedits, perms: :none, cache: :never do
  16. 4 return unless notification_act
  17. 4 wrap_subedits do
  18. 4 notification_act.actions_affecting(card).map do |action|
  19. 4 next if action.card_id == card.id
  20. action.card.format(format: @format).render_subedit_notice action_id: action.id
  21. end
  22. end
  23. end
  24. 1 view :subedit_notice, cache: :never do
  25. action = notification_action voo.action_id
  26. wrap_subedit_item do
  27. %(#{name_before_action action} #{action.action_type}d\n) +
  28. render_list_of_changes(action_id: action.id)
  29. end
  30. end
  31. 1 view :followed, perms: :none, compact: true do
  32. 4 if (set_card = followed_set_card) && (option_card = follow_option_card)
  33. 4 option_card.description set_card
  34. else
  35. "*followed set of cards*"
  36. end
  37. end
  38. 1 view :follower, perms: :none, compact: true do
  39. active_notice(:follower) || "follower"
  40. end
  41. 1 view :last_action_verb, cache: :never do
  42. 6 "#{notification_act&.main_action&.action_type || 'edite'}d"
  43. end
  44. 1 view :unfollow_url, perms: :none, compact: true, cache: :never do
  45. 4 return "" unless (rule_name = live_follow_rule_name)
  46. 4 card_url path(mark: "#{active_notice(:follower)}+#{:follow.cardname}",
  47. action: :update,
  48. card: { subcards: { rule_name => Card[:never].name } })
  49. end
  50. 1 def relevant_fields action
  51. 4 case action.action_type
  52. 4 when :create then %i[cardtype content]
  53. when :update then %i[name cardtype content]
  54. when :delete then %i[content]
  55. end
  56. end
  57. 1 def name_before_action action
  58. (action.value(:name) && action.previous_value(:name)) || card.name
  59. end
  60. 1 def followed_set_card
  61. 8 (set_name = active_notice(:followed_set)) && Card.fetch(set_name)
  62. end
  63. 1 def follow_option_card
  64. 4 return unless (option_name = active_notice(:follow_option))
  65. 4 Card.fetch option_name
  66. end
  67. 1 def active_notice key
  68. 20 @active_notice ||= inherit :active_notice
  69. 20 return unless @active_notice
  70. 20 @active_notice[key]
  71. end
  72. 1 def live_follow_rule_name
  73. 4 return unless (set_card = followed_set_card) && (follower = active_notice(:follower))
  74. 4 set_card.follow_rule_name follower
  75. end
  76. 1 def edit_info_for field, action
  77. 8 return nil unless (value = action.value field)
  78. 8 value = action.previous_value if action.action_type == :delete
  79. 8 wrap_list_item " #{notification_action_label action} #{field}: #{value}"
  80. end
  81. 1 def notification_action_label action
  82. 8 case action.action_type
  83. when :update then "new"
  84. when :delete then "deleted"
  85. end
  86. end
  87. 1 def wrap_subedits
  88. 4 subedits = yield.compact.join
  89. 4 return "" if subedits.blank?
  90. "\nThis update included the following changes:\n#{wrap_list subedits}"
  91. end
  92. 1 def wrap_list list
  93. "\n#{list}\n"
  94. end
  95. 1 def wrap_list_item item
  96. 4 "#{item}\n"
  97. end
  98. 1 def wrap_subedit_item
  99. "\n#{yield}\n"
  100. end
  101. 1 def notification_act act=nil
  102. 14 @notification_act ||= act || card.acts.last
  103. end
  104. 1 def notification_action action_id
  105. 4 action_id ? Action.fetch(action_id) : card.last_action
  106. end
  107. end
  108. end;end;end;end;end;
  109. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/all/notify/base_views.rb ~~

card/tmpsets/set/mod022-card-mod-follow/all/notify/html_views.rb

81.82% lines covered

11 relevant lines. 9 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module Notify;
  3. # Set: All cards (Notify, HtmlViews)
  4. #
  5. 1 module HtmlViews;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/all/notify/html_views.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. # view :last_action, perms: :none, cache: :never do
  10. # _render_last_action_verb
  11. # end
  12. 1 def wrap_list list
  13. "<ul>#{list}</ul>\n"
  14. end
  15. 1 def wrap_list_item item
  16. 4 "<li>#{item}</li>\n"
  17. end
  18. 1 def wrap_subedit_item
  19. "<li>#{yield}</li>\n"
  20. end
  21. end
  22. end;end;end;end;end;
  23. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/all/notify/html_views.rb ~~

card/tmpsets/set/mod022-card-mod-follow/right/account.rb

54.55% lines covered

11 relevant lines. 6 lines covered and 5 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Account" cards
  4. #
  5. 1 module Account;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/right/account.rb"; end
  8. 1 def send_change_notice act, followed_set, follow_option
  9. return unless email.present? && changes_visible?(act)
  10. notify_of_act act do
  11. { follower: left.name, followed_set: followed_set, follow_option: follow_option }
  12. end
  13. end
  14. 1 def notify_of_act act
  15. Auth.as(left.id) do
  16. Card[:follower_notification_email].deliver(
  17. act.card, { to: email }, auth: left, active_notice: yield
  18. )
  19. end
  20. end
  21. end;end;end;end;
  22. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/right/account.rb ~~

card/tmpsets/set/mod022-card-mod-follow/right/follow.rb

43.33% lines covered

60 relevant lines. 26 lines covered and 34 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Follow" cards
  4. #
  5. # The Right::Follow set configures follow preferences (`[Set]+[User]+:follow`)
  6. # While the user follow dashboard ([User]+:follow`) is also in this Set, its
  7. 1 module Follow;
  8. 1 extend Card::Set
  9. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/right/follow.rb"; end
  10. # customizations are handled in TypePlusRight::User::Follow
  11. 1 event :cache_expired_for_new_preference, :integrate, when: :is_preference? do
  12. Card.follow_caches_expired
  13. end
  14. 1 def option_cards
  15. Card::FollowOption.cards.compact
  16. end
  17. 1 def options_rule_card
  18. Card.new(
  19. name: "follow_options_card",
  20. type_code: :pointer,
  21. content: option_cards.map { |oc| "[[#{oc.name}]]" }.join("\n")
  22. )
  23. end
  24. 1 def add_follow_item? condition
  25. new_card? || !include_item?(condition)
  26. end
  27. 1 def ok_to_update
  28. permit :update
  29. end
  30. 1 def ok_to_create
  31. permit :create
  32. end
  33. 1 def ok_to_delete
  34. permit :delete
  35. end
  36. 1 def permit action, verb=nil
  37. if %i[create delete update].include?(action) && allowed_to_change_follow_status?
  38. true
  39. else
  40. super action, verb
  41. end
  42. end
  43. 1 def allowed_to_change_follow_status?
  44. Auth.signed_in? &&
  45. ((user = rule_user) && Auth.current_id == user.id) || Auth.always_ok?
  46. end
  47. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  48. # shows a follow item link for each of the current follow options
  49. 1 view :follow_status, cache: :never do
  50. wrap { haml :follow_status }
  51. end
  52. # interface to view/alter a specific rule option
  53. 1 view :follow_item, cache: :never do
  54. follow_item Env.params[:condition]
  55. end
  56. 1 def follow_item condition, button=true
  57. condition ||= "*always"
  58. wrap do
  59. card_form action: :update, success: { view: :follow_item } do
  60. [
  61. follow_item_hidden_tags(condition),
  62. (follow_item_button(condition) if button),
  63. follow_item_link(condition)
  64. ].compact
  65. end
  66. end
  67. end
  68. 1 def rule_form_args
  69. super.merge "data-update-foreign-slot": ".card-slot.follow_section-view"
  70. end
  71. 1 private
  72. 1 def follow_item_hidden_tags condition
  73. condkey = card.add_follow_item?(condition) ? :add_item : :drop_item
  74. hidden_tags condition: condition, condkey => condition
  75. end
  76. 1 def follow_item_button condition
  77. action = card.add_follow_item?(condition) ? :add : :delete
  78. button_tag type: :submit, "aria-label": "Left Align",
  79. class: "btn-sm btn-item #{follow_item_button_class action}" do
  80. follow_item_icon action
  81. end
  82. end
  83. 1 def follow_item_button_class action
  84. action == :add ? "btn-item-add" : "btn-item-delete btn-primary"
  85. end
  86. 1 def follow_item_icon action
  87. icon_tag(action == :add ? :add : :check)
  88. end
  89. 1 def follow_item_link condition
  90. link_to_card follow_item_link_target, follow_item_link_text(condition)
  91. end
  92. 1 def follow_item_link_target
  93. set = card.rule_set
  94. setname = set.name
  95. set.tag.codename == :self ? setname.left : setname.field("by name")
  96. end
  97. 1 def follow_item_link_text condition
  98. if (option_card = Card.fetch condition)
  99. option_card.description card.rule_set
  100. else
  101. card.rule_set.follow_label
  102. end
  103. end
  104. end
  105. end;end;end;end;
  106. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/right/follow.rb ~~

card/tmpsets/set/mod022-card-mod-follow/right/follow_fields.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+FollowFields" cards
  4. #
  5. 1 module FollowFields;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/right/follow_fields.rb"; end
  8. 1 event :follow_fields_changed, :integrate do
  9. Card.follow_caches_expired
  10. end
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/right/follow_fields.rb ~~

card/tmpsets/set/mod022-card-mod-follow/right/followers.rb

71.43% lines covered

14 relevant lines. 10 lines covered and 4 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Followers" cards
  4. #
  5. # -*- encoding : utf-8 -*-
  6. 1 module Followers;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/right/followers.rb"; end
  9. # X+*followers provides a list of all users following X.
  10. 1 include_set Abstract::Pointer
  11. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  12. 1 view :core, cache: :never do
  13. super()
  14. end
  15. end
  16. 1 def content
  17. left ? item_names.to_pointer_content : ""
  18. end
  19. 1 def item_names _args={}
  20. left ? left.follow_set_card.prototype.follower_names : []
  21. end
  22. 1 def virtual?
  23. new?
  24. end
  25. end;end;end;end;
  26. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/right/followers.rb ~~

card/tmpsets/set/mod022-card-mod-follow/right/following.rb

43.33% lines covered

30 relevant lines. 13 lines covered and 17 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Following" cards
  4. #
  5. 1 module Following;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/right/following.rb"; end
  8. 1 def virtual?
  9. new?
  10. end
  11. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  12. 1 view :core do
  13. if card.left && Auth.signed_in?
  14. render_rule_editor
  15. else
  16. nest Card.fetch(card.name.left, :followers), view: :titled, items: { view: :link }
  17. end
  18. end
  19. 1 view :status do
  20. if (rcard = current_follow_rule_card)
  21. rcard.item_cards.map do |item|
  22. %(<div class="alert alert-success" role="alert">
  23. <strong>#{rcard.rule_set.follow_label}</strong>: #{item.title}
  24. </div>)
  25. end.join
  26. else
  27. "No following preference"
  28. end
  29. end
  30. 1 view :one_line_content do
  31. ""
  32. end
  33. 1 view :rule_editor, cache: :never do
  34. rule_context = Card.fetch preference_name, new: { type_id: PointerID }
  35. wrap_with :div, class: "edit-rule" do
  36. follow_context = current_follow_rule_card || rule_context
  37. subformat(follow_context).rule_form :open, rule_context, :modal
  38. end
  39. end
  40. 1 def preference_name
  41. set_name = card.left.follow_set_card.name
  42. Card::Name[set_name, Auth.current.name, :follow]
  43. end
  44. 1 def edit_rule_success
  45. { view: "status", id: card.name.url_key }
  46. end
  47. 1 def current_follow_rule_card
  48. card.left.preference :follow
  49. end
  50. end
  51. end;end;end;end;
  52. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/right/following.rb ~~

card/tmpsets/set/mod022-card-mod-follow/self/always.rb

81.82% lines covered

11 relevant lines. 9 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Always"
  4. #
  5. 1 module Always;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/self/always.rb"; end
  8. 1 include_set Abstract::FollowOption
  9. 1 follow_opts position: 2
  10. 1 follow_test { |_follower_id, _accounted_ids| true }
  11. 1 def title
  12. "Following"
  13. end
  14. 1 def label
  15. "follow"
  16. end
  17. end;end;end;end;
  18. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/self/always.rb ~~

card/tmpsets/set/mod022-card-mod-follow/self/created.rb

78.57% lines covered

14 relevant lines. 11 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Created"
  4. #
  5. 1 module Created;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/self/created.rb"; end
  8. 1 include_set Abstract::FollowOption
  9. 1 restrictive_follow_opts position: 1
  10. 1 follower_candidate_ids do |card|
  11. 62 [card.creator_id]
  12. end
  13. 1 def title
  14. "Following content you created"
  15. end
  16. 1 def label
  17. "follow if I created"
  18. end
  19. 1 def description set_card
  20. "#{set_card.follow_label} I created"
  21. end
  22. end;end;end;end;
  23. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/self/created.rb ~~

card/tmpsets/set/mod022-card-mod-follow/self/edited.rb

78.57% lines covered

14 relevant lines. 11 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Edited"
  4. #
  5. 1 module Edited;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/self/edited.rb"; end
  8. 1 include_set Abstract::FollowOption
  9. 1 restrictive_follow_opts position: 2
  10. 1 follower_candidate_ids do |card|
  11. # FIXME? - could optimize by not using cards table...
  12. 62 card.id ? Card.search(editor_of: card.id, return: :id) : []
  13. end
  14. 1 def title
  15. "Following content you edited"
  16. end
  17. 1 def label
  18. "follow if I edited"
  19. end
  20. 1 def description set_card
  21. "#{set_card.follow_label} I edited"
  22. end
  23. end;end;end;end;
  24. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/self/edited.rb ~~

card/tmpsets/set/mod022-card-mod-follow/self/follow.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Follow"
  4. #
  5. 1 module Follow;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/self/follow.rb"; end
  8. 1 extend Card::Setting
  9. 1 setting_opts group: :other, position: 7, rule_type_editable: false, user_specific: true
  10. end;end;end;end;
  11. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/self/follow.rb ~~

card/tmpsets/set/mod022-card-mod-follow/self/follow_defaults.rb

35.9% lines covered

39 relevant lines. 14 lines covered and 25 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "FollowDefaults"
  4. #
  5. # DEPRECATED
  6. #
  7. # Despite its name (*follow defaults)card does not influence defaults for *follow rules.
  8. # What it does is provide a mechanism (with interface) for updating all users so that
  9. # they follow the items that are its content.
  10. #
  11. # PLAN:
  12. 1 module FollowDefaults;
  13. 1 extend Card::Set
  14. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/self/follow_defaults.rb"; end
  15. # - actual defaults should be handled as much as possible with something like
  16. # the *defaults rule
  17. # - on the *admin page, we can have a link so sharks can update all the pristine cards
  18. # to use whatever the actual defaults representation is (see previous point)
  19. # - if you truly want to override existing follow rules, that may be monkey territory?
  20. # - we will delete "*follow defaults" after the above are completed
  21. 1 event :update_follow_rules, :finalize, on: :save, when: :update_all_users do
  22. Auth.as_bot do
  23. Card.search(type: "user").each do |user|
  24. follow_defaults.each do |set_card, option|
  25. follow_rule = Card.fetch(set_card.follow_rule_name(user.name), new: {})
  26. next unless follow_rule
  27. follow_rule.drop_item "*never"
  28. follow_rule.drop_item "*always"
  29. follow_rule.add_item option
  30. follow_rule.save!
  31. end
  32. end
  33. end
  34. Card.follow_caches_expired
  35. end
  36. 1 def follow_defaults
  37. item_names.map do |item|
  38. if (set_card = Card.fetch item.to_name.left)&.type_code == :set
  39. [set_card, follow_option(item)]
  40. end
  41. end.compact
  42. end
  43. 1 def follow_option item
  44. option_card =
  45. Card.fetch(item.to_name.right) || Card[item.to_name.right.to_sym]
  46. option_card.follow_option? ? option_card.name : "*always"
  47. end
  48. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  49. 1 view :edit, perms: :update, unknown: true do
  50. frame_and_form :update, hidden: { success: "_self",
  51. card: { update_all_users: false } } do
  52. [
  53. _render_content_formgroups,
  54. _render_confirm_update_all,
  55. _render_edit_buttons
  56. ]
  57. end
  58. end
  59. 1 view :edit_buttons do
  60. button_formgroup do
  61. [submit_and_update_button, simple_submit_button, cancel_to_edit_button]
  62. end
  63. end
  64. 1 def submit_and_update_button
  65. submit_button text: "Submit and update all users",
  66. disable_with: "Updating", class: "follow-updater"
  67. end
  68. 1 def simple_submit_button
  69. button_tag "Submit", class: "follow"
  70. end
  71. 1 def cancel_to_edit_button
  72. cancel_button href: path(view: :edit, id: card.id)
  73. end
  74. 1 view :confirm_update_all do
  75. wrap do
  76. alert "info" do
  77. %(
  78. <h1>Are you sure you want to change the default follow rules?</h1>
  79. <p>You may choose to update all existing users.
  80. This may take a while. </p>
  81. )
  82. end
  83. end
  84. end
  85. end
  86. end;end;end;end;
  87. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/self/follow_defaults.rb ~~

card/tmpsets/set/mod022-card-mod-follow/self/never.rb

81.82% lines covered

11 relevant lines. 9 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "Never"
  4. #
  5. 1 module Never;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/self/never.rb"; end
  8. 1 include_set Abstract::FollowOption
  9. 1 follow_opts position: 3
  10. 1 follow_test { |_follower_id, _accounted_ids| false }
  11. 1 def title
  12. "Ignoring"
  13. end
  14. 1 def label
  15. "ignore"
  16. end
  17. end;end;end;end;
  18. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/self/never.rb ~~

card/tmpsets/set/mod022-card-mod-follow/type/cardtype.rb

66.67% lines covered

15 relevant lines. 10 lines covered and 5 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Cardtype" cards
  4. #
  5. 1 module Cardtype;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/type/cardtype.rb"; end
  8. 1 def follow_label
  9. follow_set_card.follow_label
  10. end
  11. 1 def followed_by? user_id=nil
  12. follow_set_card.all_members_followed_by? user_id
  13. end
  14. 1 def follow_set_card
  15. Card.fetch name, :type
  16. end
  17. 1 def list_direct_followers?
  18. true
  19. end
  20. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  21. 1 def related_by_type_items
  22. super.unshift ["#{card.name} cards", [card, :type, :by_name], mark: :absolute]
  23. end
  24. end
  25. end;end;end;end;
  26. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/type/cardtype.rb ~~

card/tmpsets/set/mod022-card-mod-follow/type/set.rb

61.29% lines covered

31 relevant lines. 19 lines covered and 12 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Set" cards
  4. #
  5. 1 module Set;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/type/set.rb"; end
  8. 1 event :cache_expired_for_new_set, :store, on: :create do
  9. 9 Card.follow_caches_expired
  10. end
  11. 1 def list_direct_followers?
  12. true
  13. end
  14. 1 def follow_label
  15. 4 if (klass = subclass_for_set)
  16. 4 klass.short_label name.left_name
  17. else
  18. ""
  19. end
  20. end
  21. 1 def follow_rule_name user=nil
  22. 4 Card::Name[[name, user, :follow].compact]
  23. end
  24. 1 def followed_by? user_id=nil
  25. all_members_followed_by? user_id
  26. end
  27. 1 def follow_set_card
  28. self
  29. end
  30. 1 def all_members_followed?
  31. all_members_followed_by? Auth.current_id
  32. end
  33. 1 def all_members_followed_by? user_id=nil
  34. return false unless prototype.followed_by?(user_id)
  35. directly_followed_by?(user_id) || broader_set_followed_by?(user_id)
  36. end
  37. 1 def broader_set_followed_by? user_id
  38. broader_sets.find do |set_name|
  39. Card.fetch(set_name)&.directly_followed_by? user_id
  40. end
  41. end
  42. 1 def directly_followed?
  43. directly_followed_by? Auth.current_id
  44. end
  45. 1 def directly_followed_by? user_id=nil
  46. return true if user_id && follow_rule?(user_id)
  47. follow_rule?
  48. end
  49. end;end;end;end;
  50. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/type/set.rb ~~

card/tmpsets/set/mod022-card-mod-follow/type/user.rb

55.56% lines covered

9 relevant lines. 5 lines covered and 4 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "User" cards
  4. #
  5. 1 module User;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/type/user.rb"; end
  8. 1 def follow follow_name, option="*always"
  9. return unless (follow_rule = Card.fetch(follow_name)&.follow_rule_card(name, new: {}))
  10. follow_rule.drop_item "*never"
  11. follow_rule.add_item option
  12. follow_rule.save!
  13. end
  14. end;end;end;end;
  15. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/type/user.rb ~~

card/tmpsets/set/mod022-card-mod-follow/type_plus_right/user/follow.rb

45.24% lines covered

42 relevant lines. 19 lines covered and 23 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class TypePlusRight; module User;
  3. # Set: All "+Follow" cards on "User" cards
  4. #
  5. 1 module Follow;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/type_plus_right/user/follow.rb"; end
  8. 1 FOLLOW_TABS = { "Follow" => "follow_tab", "Ignore" => "ignore_tab" }.freeze
  9. # a virtual pointer to the sets that a user is following.
  10. # (data is stored in preferences: `[Set]+[User]+:follow`)
  11. 1 include_set Abstract::Pointer
  12. 1 def virtual?
  13. new?
  14. end
  15. # overrides pointer default
  16. 1 def item_names _args={}
  17. if (user = left)
  18. Card::Rule.preference_names user.name, "follow"
  19. else
  20. []
  21. end
  22. end
  23. 1 def suggestions
  24. Card[:follow_suggestions]&.item_names || []
  25. end
  26. 1 def current_user?
  27. Auth.signed_in? && Auth.current_id == left.id
  28. end
  29. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  30. 1 view :one_line_content do
  31. ""
  32. end
  33. 1 view :edit do
  34. render :open
  35. end
  36. # renders follow tab and ignore tab
  37. 1 view :core do
  38. tabs FOLLOW_TABS, "follow_tab", load: :lazy do
  39. render_follow_tab
  40. end
  41. end
  42. 1 view :follow_tab, cache: :never do
  43. haml :follow_editor, items_method: :following_rules_and_options
  44. end
  45. 1 view :ignore_tab, cache: :never do
  46. haml :follow_editor, items_method: :ignoring_rules_and_options
  47. end
  48. 1 def show_button?
  49. card.current_user? || Auth.always_ok?
  50. end
  51. 1 def pointer_items args
  52. voo.items[:view] ||= :link
  53. super(args)
  54. end
  55. # TODO: research and generalize
  56. # this does not look specific to following!
  57. 1 view :errors, perms: :none do
  58. return unless card.errors.any?
  59. if card.errors.find { |attrib, _msg| attrib == :permission_denied }
  60. Env.save_interrupted_action(request.env["REQUEST_URI"])
  61. voo.title = "Problems with #{card.name}"
  62. class_up "d0-card-frame", "card card-warning card-inverse"
  63. frame do
  64. "Please #{link_to_card :signin, 'sign in'}" # " #{to_task}"
  65. end
  66. else
  67. super()
  68. end
  69. end
  70. end
  71. end;end;end;end;end;
  72. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/type_plus_right/user/follow.rb ~~

card/tmpsets/set/mod022-card-mod-follow/type_plus_right/user/follow/follow_editor_helper.rb

31.67% lines covered

60 relevant lines. 19 lines covered and 41 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 5 class Card; module Set; class TypePlusRight; module User;; module Follow;
  3. # Set: All "+FollowEditorHelper" cards on "User+Follow" cards (FollowEditorHelper)
  4. #
  5. # all the following methods are used to construct the Follow and Ignore tabs
  6. 1 module FollowEditorHelper;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-follow/set/type_plus_right/user/follow/follow_editor_helper.rb"; end
  9. # TODO: these object representations are complex enough for their own class
  10. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  11. # constructs hash of rules/options for "Follow" tab
  12. 1 def following_rules_and_options &block
  13. rule_opt_array = following_rule_options_hash.map do |key, val|
  14. [(Card.fetch key, new: {}), val]
  15. end
  16. rules_and_options_by_set_pattern Hash[rule_opt_array], &block
  17. end
  18. # constructs hash of rules/options for "Ignore" tab
  19. 1 def ignoring_rules_and_options &block
  20. rule_opts_hash = ignore_rules.each_with_object({}) do |rule, hash|
  21. hash[rule] = [:never.cardname]
  22. end
  23. rules_and_options_by_set_pattern rule_opts_hash, &block
  24. end
  25. 1 private
  26. # all rules with ignore
  27. 1 def ignore_rules
  28. never = :never.cardname.key
  29. card.item_cards.select do |follow_rule|
  30. follow_rule.item_names.select { |n| n.key == never }.any?
  31. end
  32. end
  33. # @param rule_opts_hash [Hash] { rule1_card => rule1_follow_options }
  34. # for each rule/option variant, yields with rule_card and option params
  35. 1 def rules_and_options_by_set_pattern rule_opts_hash
  36. pattern_hash = a_set_pattern_hash rule_opts_hash
  37. empty = true
  38. Card.set_patterns.reverse.map do |pattern|
  39. pattern_hash[pattern].each do |rule_card, options|
  40. options.each do |option|
  41. yield rule_card, option
  42. empty = false
  43. end
  44. end
  45. end
  46. yield nil if empty
  47. end
  48. 1 def a_set_pattern_hash rule_opts_hash
  49. pattern_hash = Hash.new { |h, k| h[k] = [] }
  50. rule_opts_hash.each do |rule_card, options|
  51. pattern_hash[rule_card.rule_set.subclass_for_set] << [rule_card, options]
  52. end
  53. pattern_hash
  54. end
  55. # @return Hash # { rule1 => rule1_follow_options }
  56. 1 def following_rule_options_hash
  57. merge_option_hashes current_following_rule_options_hash,
  58. suggested_following_rule_options_hash
  59. end
  60. # adds suggested follow options to existing rules where applicable
  61. 1 def merge_option_hashes current, suggested
  62. current.each do |key, current_opt|
  63. if (suggested_opt = suggested.delete(key))
  64. current[key] = (current_opt + suggested_opt).uniq
  65. end
  66. end
  67. current.merge suggested
  68. end
  69. # @return Hash # { existing_rule1 => rule1_follow_options } (excluding never)
  70. # (*never is excluded because this list is for the Follow tab, and *never is
  71. # handled under the Ignore tab)
  72. 1 def current_following_rule_options_hash
  73. never = :never.cardname
  74. card.item_cards.each_with_object({}) do |follow_rule, hash|
  75. hash[follow_rule.key] = follow_rule.item_names.reject { |item| item == never }
  76. end
  77. end
  78. # @return Hash # { suggested_rule1 => rule1_follow_options }
  79. 1 def suggested_following_rule_options_hash
  80. return {} unless card.current_user?
  81. card.suggestions.each_with_object({}) do |sug, hash|
  82. set_card, opt = a_set_and_option_suggestion(sug) || a_set_only_suggestion(sug)
  83. hash[set_card.follow_rule_name(card.trunk).key] = [opt]
  84. end
  85. end
  86. # @param sug [String] follow suggestion
  87. # @return [Array] set_card and option
  88. # suggestion value contains both set and follow option
  89. 1 def a_set_and_option_suggestion sug
  90. return unless (set_card = valid_set_card(sug.to_name.left))
  91. [set_card, suggested_follow_option(sug.to_name.right)]
  92. end
  93. 1 def suggested_follow_option name
  94. # FIXME: option should be unambiguously name or codename
  95. # (if codename use colon or Symbol)
  96. option_card = Card.fetch(name) || Card[name.to_sym]
  97. option_card&.follow_option? ? option_card.name : :always.cardname
  98. end
  99. # @param sug [String] follow suggestion
  100. # @return [Array] set_card and option
  101. # suggestion value contains only set (implies *always)
  102. 1 def a_set_only_suggestion sug
  103. return unless (set_card = valid_set_card(sug))
  104. yield set_card, :always.cardname
  105. end
  106. 1 def valid_set_card name
  107. card = Card.fetch(name)
  108. card&.type_code == :set ? card : false
  109. end
  110. end
  111. end;end;end;end;end;end;
  112. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-follow/set/type_plus_right/user/follow/follow_editor_helper.rb ~~

card/tmpsets/set/mod023-card-mod-google_analytics/all/google_analytics.rb

83.33% lines covered

24 relevant lines. 20 lines covered and 4 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (GoogleAnalytics)
  4. #
  5. 1 module GoogleAnalytics;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-google_analytics/set/all/google_analytics.rb"; end
  8. 1 require "staccato"
  9. 1 mattr_accessor :server_side_tracking_formats
  10. 1 self.server_side_tracking_formats = %i[csv json]
  11. 1 event :track_page, before: :show_page, when: :track_page? do
  12. tracker.pageview path: Env.controller.request&.path, host: Env.host, title: name
  13. end
  14. 1 def track_page?
  15. 31 google_analytics_key &&
  16. Env.controller&.response_format&.in?(server_side_tracking_formats)
  17. end
  18. 1 def tracker
  19. return unless google_analytics_key
  20. ::Staccato.tracker google_analytics_key # , nil, ssl: true
  21. end
  22. 1 def google_analytics_key
  23. 54 @google_analytics_key ||=
  24. Card::Rule.global_setting(:google_analytics_key) ||
  25. Card.config.google_analytics_key
  26. end
  27. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  28. 1 delegate :tracker, :google_analytics_key, to: :card
  29. 1 def views_in_head
  30. 23 super << :google_analytics_snippet
  31. end
  32. 1 view :google_analytics_snippet, unknown: true, perms: :none do
  33. 23 haml :google_analytics_snippet if google_analytics_key
  34. end
  35. 1 def google_analytics_snippet_vars
  36. { anonymizeIp: true }
  37. end
  38. end
  39. end;end;end;end;
  40. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-google_analytics/set/all/google_analytics.rb ~~

card/tmpsets/set/mod024-card-mod-markdown/type/markdown.rb

84.62% lines covered

13 relevant lines. 11 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Markdown" cards
  4. #
  5. 1 module Markdown;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-markdown/set/type/markdown.rb"; end
  8. 1 require "kramdown"
  9. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  10. 1 view :core do
  11. 10 safe_process_content do |content|
  12. 10 Kramdown::Document.new(content).to_html
  13. end
  14. end
  15. 1 def input_type
  16. :ace_editor
  17. end
  18. 1 def ace_mode
  19. :markdown
  20. end
  21. end
  22. end;end;end;end;
  23. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-markdown/set/type/markdown.rb ~~

card/tmpsets/set/mod025-card-mod-prosemirror_editor/all/prosemirror_editor.rb

75.0% lines covered

8 relevant lines. 6 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (ProsemirrorEditor)
  4. #
  5. 1 module ProsemirrorEditor;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-prosemirror_editor/set/all/prosemirror_editor.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def prosemirror_editor_input
  10. wrap_with :div, id: unique_id, class: "prosemirror-editor" do
  11. hidden_field :content, class: "d0-card-content", value: card.content
  12. end
  13. end
  14. end
  15. end;end;end;end;
  16. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-prosemirror_editor/set/all/prosemirror_editor.rb ~~

card/tmpsets/set/mod025-card-mod-prosemirror_editor/self/script_prosemirror.rb

100.0% lines covered

7 relevant lines. 7 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ScriptProsemirror"
  4. #
  5. 1 module ScriptProsemirror;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-prosemirror_editor/set/self/script_prosemirror.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 Self::ScriptMods.add_item :script_prosemirror
  10. 1 Self::InputOptions.add_to_basket :options, "prosemirror editor"
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-prosemirror_editor/set/self/script_prosemirror.rb ~~

card/tmpsets/set/mod025-card-mod-prosemirror_editor/self/script_prosemirror_config.rb

100.0% lines covered

7 relevant lines. 7 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ScriptProsemirrorConfig"
  4. #
  5. 1 module ScriptProsemirrorConfig;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-prosemirror_editor/set/self/script_prosemirror_config.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 Self::ScriptEditors.add_item :script_prosemirror_config
  10. 1 All::Head::HtmlFormat.add_to_basket :mod_js_config,
  11. [:prose_mirror, "setProseMirrorConfig"]
  12. end;end;end;end;
  13. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-prosemirror_editor/set/self/script_prosemirror_config.rb ~~

card/tmpsets/set/mod025-card-mod-prosemirror_editor/self/style_prosemirror.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "StyleProsemirror"
  4. #
  5. 1 module StyleProsemirror;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-prosemirror_editor/set/self/style_prosemirror.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 Self::StyleMods.add_item :style_prosemirror
  10. end;end;end;end;
  11. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-prosemirror_editor/set/self/style_prosemirror.rb ~~

card/tmpsets/set/mod026-card-mod-recaptcha/all/recaptcha.rb

62.0% lines covered

50 relevant lines. 31 lines covered and 19 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (Recaptcha)
  4. #
  5. 1 module Recaptcha;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-recaptcha/set/all/recaptcha.rb"; end
  8. RECAPTCHA_ERROR_CODES = { # LOCALIZE
  9. 1 "missing-input-secret" => "secret parameter is missing",
  10. "invalid-input-secret" => "secret parameter is invalid or malformed",
  11. "missing-input-response" => "response parameter is missing",
  12. "invalid-input-response" => "response parameter is invalid or malformed",
  13. "bad-request" => "request is invalid or malformed"
  14. }
  15. 1 def human?
  16. result = JSON.parse recaptcha_response
  17. return if recaptcha_success?(result)
  18. add_recaptcha_errors result["error-codes"]
  19. end
  20. 1 def recaptcha_on?
  21. 185 recaptcha_keys? &&
  22. Env[:controller] &&
  23. !Auth.signed_in? &&
  24. !Auth.always_ok? &&
  25. !Auth.needs_setup? &&
  26. Card::Rule.toggle(rule(:captcha))
  27. end
  28. 1 def add_recaptcha_errors error_codes
  29. if error_codes.present?
  30. error_codes.each do |code|
  31. errors.add :recaptcha, RECAPTCHA_ERROR_CODES.fetch(code, code)
  32. end
  33. else
  34. errors.add :recaptcha, "Looks like you are not a human" # LOCALIZE
  35. end
  36. end
  37. 1 def recaptcha_success? result
  38. result['success'] &&
  39. (result['score'].to_f >= Cardio.config.recaptcha_minimum_score) &&
  40. (result['action'].to_sym == action.to_sym)
  41. end
  42. 1 def recaptcha_response
  43. ::Recaptcha.get({ secret: Card.config.recaptcha_secret_key,
  44. response: Env.params[:recaptcha_token] }, {})
  45. end
  46. 1 def recaptcha_keys?
  47. 185 Card.config.recaptcha_site_key && Card.config.recaptcha_secret_key
  48. end
  49. 1 event :recaptcha, :validate, when: :validate_recaptcha? do
  50. handle_recaptcha_config_errors do
  51. Env[:recaptcha_used] = true
  52. human?
  53. end
  54. end
  55. 1 def handle_recaptcha_config_errors
  56. if Env.params[:recaptcha_token] == "grecaptcha-undefined"
  57. errors.add "recaptcha", "needs correct v3 configuration" # LOCALILZE
  58. elsif Env.params[:recaptcha_token] == "recaptcha-token-field-missing"
  59. raise Card::Error, "recaptcha token field missing" # LOCALILZE
  60. else
  61. yield
  62. end
  63. end
  64. 1 def validate_recaptcha?
  65. 332 !@supercard && !Env[:recaptcha_used] && recaptcha_on?
  66. end
  67. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  68. 1 def recaptcha_token action
  69. 1 output [
  70. javascript_include_tag(recaptcha_script_url),
  71. hidden_field_tag("recaptcha_token", "",
  72. "data-site-key": Card.config.recaptcha_site_key,
  73. "data-action": action,
  74. class: "_recaptcha-token")
  75. ]
  76. end
  77. 1 def recaptcha_script_url
  78. 1 "https://www.google.com/recaptcha/api.js?render=#{Card.config.recaptcha_site_key}"
  79. end
  80. 1 def hidden_form_tags action, opts
  81. 20 return super unless recaptcha?(opts)
  82. 1 super + recaptcha_token(action)
  83. end
  84. 1 def card_form_html_opts action, opts={}
  85. 20 super
  86. 20 opts["data-recaptcha"] ||= "on" if recaptcha?(opts)
  87. 20 opts
  88. end
  89. 1 def recaptcha? opts
  90. 40 card.recaptcha_on? && opts[:recaptcha] != :off
  91. end
  92. end
  93. end;end;end;end;
  94. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-recaptcha/set/all/recaptcha.rb ~~

card/tmpsets/set/mod026-card-mod-recaptcha/self/admin_info.rb

56.25% lines covered

16 relevant lines. 9 lines covered and 7 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "AdminInfo"
  4. #
  5. 1 module AdminInfo;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-recaptcha/set/self/admin_info.rb"; end
  8. 1 add_to_basket :warnings, :recaptcha_config_issues
  9. 1 def recaptcha_config_issues?
  10. RecaptchaCard.using_defaults?
  11. end
  12. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  13. 1 def recaptcha_config_issues_message
  14. warning =
  15. if Card::Env.localhost?
  16. # %(Your captcha is currently working with temporary settings.
  17. # This is fine for a local installation, but you will need new
  18. # recaptcha keys if you want to make this site public.)
  19. I18n.t(:captcha_temp, scope: "mod.admin.set.self.admin_info",
  20. recaptcha_link: add_recaptcha_keys_link)
  21. else
  22. # %(You are configured to use [[*captcha]], but for that to work
  23. # you need new recaptcha keys.)
  24. I18n.t(:captcha_keys, scope: "mod.admin.set.self.admin_info",
  25. recaptcha_link: add_recaptcha_keys_link,
  26. captcha_link: link_to_card(:captcha))
  27. end
  28. <<-HTML
  29. <p>#{warning}</p>
  30. HTML
  31. end
  32. 1 def add_recaptcha_keys_link
  33. link_text = I18n.t :recaptcha_keys, scope: "mod.admin.set.self.admin_info"
  34. Card[:recaptcha_settings]&.format&.edit_link link_text: link_text
  35. end
  36. end
  37. end;end;end;end;
  38. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-recaptcha/set/self/admin_info.rb ~~

card/tmpsets/set/mod026-card-mod-recaptcha/self/recaptcha_proxy.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "RecaptchaProxy"
  4. #
  5. 1 module RecaptchaProxy;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-recaptcha/set/self/recaptcha_proxy.rb"; end
  8. 1 event :set_recaptcha_proxy, :finalize do
  9. Card.config.recaptcha_proxy = content
  10. end
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-recaptcha/set/self/recaptcha_proxy.rb ~~

card/tmpsets/set/mod026-card-mod-recaptcha/self/recaptcha_secret_key.rb

66.67% lines covered

9 relevant lines. 6 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "RecaptchaSecretKey"
  4. #
  5. 1 module RecaptchaSecretKey;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-recaptcha/set/self/recaptcha_secret_key.rb"; end
  8. 1 event :validate_recaptcha_secret_key, :validate do
  9. return if content.match?(/^[a-zA-Z0-9\-_]*$/)
  10. errors.add :content, "invalid key" # LOCALIZE
  11. end
  12. 1 event :set_recaptcha_secret_key, :finalize do
  13. Card.config.recaptcha_secret_key = content
  14. end
  15. end;end;end;end;
  16. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-recaptcha/set/self/recaptcha_secret_key.rb ~~

card/tmpsets/set/mod026-card-mod-recaptcha/self/recaptcha_settings.rb

85.71% lines covered

7 relevant lines. 6 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "RecaptchaSettings"
  4. #
  5. 1 module RecaptchaSettings;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-recaptcha/set/self/recaptcha_settings.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def raw_help_text
  10. # LOCALIZE
  11. "Register your domain at Google's [[http://google.com/recaptcha|reCAPTCHA service]] "\
  12. "and enter your site key and secret key below.<br>"\
  13. "If you want to turn catchas off then change all [[*captcha|captcha rules]] to 'no'."
  14. end
  15. # def instructions title, steps
  16. # steps = list_tag steps, ordered: true
  17. # "#{title}#{steps}"
  18. # end
  19. #
  20. # <h5>#{instructions}</h5>
  21. # #{howto_add_new_recaptcha_keys}
  22. # #{howto_turn_captcha_off}
  23. #
  24. # def howto_add_new_recaptcha_keys
  25. # instructions(
  26. # I18n.t(:howto_add_keys, scope: "mod.admin.set.self.admin_info"),
  27. # [
  28. # I18n.t(:howto_register,
  29. # scope: "mod.admin.set.self.admin_info",
  30. # recaptcha_link: link_to_resource("http://google.com/recaptcha")),
  31. # I18n.t(:howto_add,
  32. # scope: "mod.admin.set.self.admin_info",
  33. # recaptcha_settings: link_to_card(:recaptcha_settings))
  34. # ]
  35. # )
  36. # end
  37. #
  38. # def howto_turn_captcha_off
  39. # instructions(
  40. # I18n.t(:howto_turn_off, scope: "mod.admin.set.self.admin_info"),
  41. # [
  42. # I18n.t(:howto_go,
  43. # scope: "mod.admin.set.self.admin_info",
  44. # captcha_card: link_to_card(:captcha)),
  45. # I18n.t(:howto_update,
  46. # scope: "mod.admin.set.self.admin_info")
  47. # ]
  48. # )
  49. # end
  50. end
  51. end;end;end;end;
  52. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-recaptcha/set/self/recaptcha_settings.rb ~~

card/tmpsets/set/mod026-card-mod-recaptcha/self/recaptcha_site_key.rb

66.67% lines covered

9 relevant lines. 6 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "RecaptchaSiteKey"
  4. #
  5. 1 module RecaptchaSiteKey;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-recaptcha/set/self/recaptcha_site_key.rb"; end
  8. 1 event :validate_recaptcha_site_key, :validate do
  9. return if content.match?(/^[a-zA-Z0-9\-_]*$/)
  10. errors.add :content, "invalid key" # LOCALIZE
  11. end
  12. 1 event :set_recaptcha_site_key, :finalize do
  13. Card.config.recaptcha_site_key = content
  14. end
  15. end;end;end;end;
  16. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-recaptcha/set/self/recaptcha_site_key.rb ~~

card/tmpsets/set/mod027-card-mod-rules/right/self.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Self" cards
  4. #
  5. 1 module Self;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-rules/set/right/self.rb"; end
  8. 1 def prototype_default_card
  9. left
  10. end
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-rules/set/right/self.rb ~~

card/tmpsets/set/mod027-card-mod-rules/rstar/rule_user.rb

75.0% lines covered

8 relevant lines. 6 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Rstar
  3. # Set: All "+*" cards (RuleUser)
  4. #
  5. 1 module RuleUser;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-rules/set/rstar/rule_user.rb"; end
  8. 1 def rule_user_name
  9. is_preference? ? name.trunk_name.tag : nil
  10. end
  11. 1 def rule_user
  12. is_preference? ? self[-2] : nil
  13. end
  14. end;end;end;end;
  15. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-rules/set/rstar/rule_user.rb ~~

card/tmpsets/set/mod027-card-mod-rules/rule/bar_view.rb

46.94% lines covered

49 relevant lines. 23 lines covered and 26 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Rule
  3. # Set: All rule cards (BarView)
  4. #
  5. 1 module BarView;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/bar_view.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 bar_cols 6, 6
  10. 1 info_bar_cols 5, 4, 3
  11. 1 def existing_rule_card
  12. @existing_rule_card ||= find_existing_rule_card
  13. end
  14. 1 view :bar, unknown: true do
  15. voo.hide :bar_nav unless existing_rule_card
  16. super()
  17. end
  18. 1 view :expanded_bar, unknown: true do
  19. super()
  20. end
  21. 1 view :one_line_content,
  22. wrap: { div: { class: "text-muted one-line" } }, unknown: true do
  23. return render_mini_unknown unless existing_rule_card
  24. with_nest_mode :compact do
  25. one_line_content
  26. end
  27. end
  28. 1 view :raw_one_line_content,
  29. wrap: { div: { class: "text-muted one-line" } }, unknown: true do
  30. return render_mini_unknown unless existing_rule_card
  31. raw_one_line_content
  32. end
  33. 1 view :bar_bottom, unknown: true do
  34. if nest_mode == :edit
  35. current_rule_form
  36. else
  37. nest existing_rule_card, view: :core
  38. end
  39. end
  40. 1 view :bar_middle, unknown: true do
  41. rule_info
  42. end
  43. 1 view :bar_left, unknown: true do
  44. super()
  45. end
  46. 1 view :bar_right, unknown: true do
  47. voo.show?(:bar_bottom) ? rule_info : rule_short_content
  48. end
  49. 1 def rule_short_content
  50. return "" unless existing_rule_card
  51. nest existing_rule_card, { view: :one_line_content },
  52. set_context: card.name.trunk_name
  53. end
  54. 1 def bar_title
  55. return super() if voo.show? :full_name
  56. linking_to_existing_rule { card.rule_setting_title }
  57. end
  58. # LOCALIZE
  59. 1 def rule_info
  60. return wrap_with(:em, "no existing #{setting_link} rule") unless existing_rule_card
  61. wrap_with :span,
  62. "#{rule_setting_link} rule that applies to "\
  63. "#{rule_set_link existing_rule_card}"
  64. end
  65. 1 def rule_setting_link
  66. link_to_card card.rule_setting, card.rule_setting_name
  67. end
  68. 1 def rule_set_link existing_rule
  69. count = link_to_card [card.rule_set, :by_name], card.rule_set.count
  70. "#{link_to_card card.rule_set, existing_rule.trunk&.label&.downcase} (#{count})"
  71. end
  72. 1 private
  73. 1 def linking_to_existing_rule
  74. return yield unless existing_rule_card && voo.show?(:toggle)
  75. link_to_view bar_title_toggle_view, yield
  76. end
  77. end
  78. end;end;end;end;
  79. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/bar_view.rb ~~

card/tmpsets/set/mod027-card-mod-rules/rule/bridge_rules_editor.rb

55.56% lines covered

18 relevant lines. 10 lines covered and 8 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Rule
  3. # Set: All rule cards (BridgeRulesEditor)
  4. #
  5. 1 module BridgeRulesEditor;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/bridge_rules_editor.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :overlay_rule, cache: :never, unknown: true do
  10. wrap_with_overlay slot: breadcrumb_data("Rule editing", "rules") do
  11. current_rule_form
  12. end
  13. end
  14. 1 view :modal_rule, cache: :never, unknown: true,
  15. wrap: { modal: { title: ->(format) { format.render_title } } } do
  16. current_rule_form
  17. end
  18. 1 view :overlay_title do
  19. edit_rule_title
  20. end
  21. 1 view :help_text, unknown: true, cache: :never do
  22. wrap_help_text [rule_based_help, setting_link].join(" ")
  23. end
  24. 1 def setting_link
  25. wrap_with :div, class: "ml-auto" do
  26. link_to_card card.rule_setting_name,
  27. " (#{card.rule_setting.count} #{card.rule_setting_title} rules)",
  28. class: "text-muted"
  29. end
  30. end
  31. end
  32. end;end;end;end;
  33. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/bridge_rules_editor.rb ~~

card/tmpsets/set/mod027-card-mod-rules/rule/editor.rb

42.59% lines covered

54 relevant lines. 23 lines covered and 31 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Rule
  3. # Set: All rule cards (Editor)
  4. #
  5. 1 module Editor;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/editor.rb"; end
  8. 1 def left_type_for_nest_editor_set_selection
  9. return super unless is_template?
  10. case Card.fetch_id rule_set_pattern_name
  11. when TypeID
  12. rule_set.anchor_name
  13. when SelfID
  14. rule_set.anchor.type_name
  15. else
  16. super
  17. end
  18. end
  19. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  20. 1 attr_accessor :rule_context
  21. 1 view :rule_edit, cache: :never, unknown: true,
  22. wrap: { modal: { size: :large,
  23. title: :edit_rule_title,
  24. footer: "" } } do
  25. current_rule_form form_type: :modal
  26. end
  27. 1 view :rule_help, unknown: true, perms: :none, cache: :never do
  28. wrap_with :div, class: "alert alert-info rule-instruction" do
  29. rule_based_help
  30. end
  31. end
  32. 1 view :rule_bridge_link, unknown: true do
  33. opts = bridge_link_opts(class: "edit-rule-link nav-link",
  34. "data-toggle": "pill",
  35. "data-cy": "#{setting_title.to_name.key}-pill")
  36. opts[:path].delete(:layout)
  37. link_to_view(:overlay_rule, (setting_title + short_help_text), opts)
  38. end
  39. 1 def edit_link_view
  40. :rule_edit
  41. end
  42. 1 def edit_rule_title
  43. output [
  44. wrap_with(:h5, setting_title, class: "title font-weight-bold")
  45. # render_overlay_rule_help
  46. ]
  47. end
  48. 1 def current_rule
  49. if params[:assign]
  50. card
  51. elsif (existing = find_existing_rule_card)
  52. existing
  53. else
  54. card
  55. end
  56. end
  57. 1 def quick_editor
  58. rule_content_formgroup
  59. end
  60. 1 def setting_title
  61. card.name.tag.tr "*", ""
  62. end
  63. 1 def short_help_text
  64. "<div class=\"help-text\">#{card.short_help_text}</div>"
  65. end
  66. 1 def rule_set_description
  67. card.rule_set.follow_label
  68. end
  69. 1 def rules_type_formgroup
  70. return unless card.right.rule_type_editable
  71. success = @edit_rule_success
  72. wrap_type_formgroup do
  73. type_field(
  74. href: path(mark: success[:id], view: :rule_form, assign: true),
  75. class: "type-field rule-type-field live-type-field",
  76. "data-remote" => true
  77. )
  78. end
  79. end
  80. 1 def rule_content_formgroup
  81. _render_content_formgroup hide: :conflict_tracker
  82. end
  83. 1 def current_set_key
  84. card.new_card? ? Card.quick_fetch(:all).name.key : card.rule_set_key
  85. end
  86. 1 private
  87. 1 def find_existing_rule_card
  88. card.new_card? ? existing_rule_from_prototype : card
  89. end
  90. # self.card is a POTENTIAL rule; it quacks like a rule but may or may not exist.
  91. # This generates a prototypical member of the POTENTIAL rule's set
  92. # and returns that member's ACTUAL rule for the POTENTIAL rule's setting
  93. 1 def existing_rule_from_prototype
  94. return unless (setting = card.right)
  95. card.set_prototype.rule_card setting.codename, user: card.rule_user
  96. end
  97. end
  98. end;end;end;end;
  99. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/editor.rb ~~

card/tmpsets/set/mod027-card-mod-rules/rule/html_views.rb

88.89% lines covered

9 relevant lines. 8 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Rule
  3. # Set: All rule cards (HtmlViews)
  4. #
  5. 1 module HtmlViews;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/html_views.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :core do
  10. # Rule cards that are searches are usual right structures and refer to the left
  11. # in the search query. In that case the search doesn't work
  12. # properly in the context of the rule card itself. Hence we show the query syntax
  13. # and not the search result.
  14. 10 if card.type_id == SearchTypeID
  15. render_raw
  16. else
  17. 10 super()
  18. end
  19. end
  20. end
  21. end;end;end;end;
  22. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/html_views.rb ~~

card/tmpsets/set/mod027-card-mod-rules/rule/quick_editor.rb

57.14% lines covered

21 relevant lines. 12 lines covered and 9 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Rule
  3. # Set: All rule cards (QuickEditor)
  4. #
  5. 1 module QuickEditor;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/quick_editor.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :quick_edit, unknown: true, wrap: :slot do
  10. quick_edit
  11. end
  12. 1 view :quick_edit_success do
  13. set_info true
  14. end
  15. 1 def quick_edit
  16. haml :quick_edit
  17. end
  18. 1 def quick_form
  19. card_form :update, quick_form_opts do
  20. quick_editor
  21. end
  22. end
  23. 1 def quick_form_opts
  24. { "data-slot-selector": ".set-info.card-slot",
  25. success: { view: :quick_edit_success } }
  26. end
  27. 1 def set_info notify_change=nil
  28. wrap true, class: "set-info" do
  29. haml :set_info, notify_change: notify_change
  30. end
  31. end
  32. 1 def undo_button
  33. link_to "undo", method: :post, rel: "nofollow", remote: true,
  34. class: "btn btn-secondary ml-2 btn-sm btn-reduced-padding slotter",
  35. "data-slot-selector": ".card-slot.quick_edit-view",
  36. path: { action: :update,
  37. revert_actions: [card.last_action_id],
  38. revert_to: :previous }
  39. end
  40. end
  41. end;end;end;end;
  42. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/quick_editor.rb ~~

card/tmpsets/set/mod027-card-mod-rules/rule/rule_form.rb

37.14% lines covered

35 relevant lines. 13 lines covered and 22 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Rule
  3. # Set: All rule cards (RuleForm)
  4. #
  5. 1 module RuleForm;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/rule_form.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :rule_form, cache: :never, unknown: true do
  10. @success_view ||= :open
  11. @rule_context ||= card
  12. @form_type ||= :overlay
  13. wrap do
  14. edit_rule_form @success_view do
  15. [
  16. hidden_tags(success: @edit_rule_success),
  17. haml(:rule_form)
  18. ].join
  19. end
  20. end
  21. end
  22. 1 def form_type
  23. @form_type || :overlay
  24. end
  25. 1 def current_rule_form success_view: :overlay_rule, form_type: :overlay
  26. current_rule_format = subformat current_rule
  27. current_rule_format.rule_form success_view, card, form_type
  28. end
  29. 1 def rule_form success_view, rule_context, form_type=:overlay
  30. validate_form_type form_type
  31. @rule_context = rule_context
  32. @form_type = form_type
  33. @success_view = success_view
  34. render_rule_form
  35. end
  36. 1 def validate_form_type form_type
  37. return if form_type.in? %i[overlay modal]
  38. raise "invalid rule_form type: #{form_type}; has to be overlay or modal"
  39. end
  40. 1 def edit_rule_form success_view, &block
  41. @rule_context ||= card
  42. @edit_rule_success = edit_rule_success(success_view)
  43. action_args = { action: :update, no_mark: true }
  44. card_form action_args, rule_form_args, &block
  45. end
  46. 1 def rule_form_args
  47. { class: "card-rule-form", "data-slotter-mode": "update-origin" }
  48. end
  49. 1 def edit_rule_success view="overlay_rule"
  50. { id: @rule_context.name.url_key,
  51. view: view }
  52. end
  53. end
  54. end;end;end;end;
  55. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/rule_form.rb ~~

card/tmpsets/set/mod027-card-mod-rules/rule/rule_form/buttons.rb

43.48% lines covered

23 relevant lines. 10 lines covered and 13 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Rule; module RuleForm;
  3. # Set: All rule cards (RuleForm, Buttons)
  4. #
  5. 1 module Buttons;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/rule_form/buttons.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def edit_rule_buttons
  10. wrap_with(:div, class: "button-area") do
  11. [
  12. standard_save_button(class: "_rule-submit-button"),
  13. standard_save_and_close_button(class: "_rule-submit-button", close: form_type),
  14. edit_rule_cancel_button,
  15. edit_rule_delete_button
  16. ]
  17. end
  18. end
  19. 1 def edit_rule_cancel_button
  20. send "#{form_type}_close_button", "Cancel", situation: "secondary", class: "btn-sm"
  21. end
  22. 1 def edit_rule_delete_button args={}
  23. return if card.new_card?
  24. delete_opts = {
  25. confirm: delete_confirm(args[:fallback_set]),
  26. # success: @edit_rule_success,
  27. no_success: true,
  28. "data-slotter-mode": "silent-success",
  29. class: "_close-#{form_type}-on-success"
  30. }
  31. delete_opts["data-slot-selector"] = slot_selector if args[:slot_selector]
  32. wrap_with :span, class: "rule-delete-section" do
  33. delete_button delete_opts
  34. end
  35. end
  36. 1 def delete_confirm fallback_set
  37. setting = card.rule_setting_name
  38. if fallback_set && (fallback_set_card = Card.fetch(fallback_set))
  39. "Deleting will revert to #{setting} rule for #{fallback_set_card.label}"
  40. else
  41. "Are you sure you want to delete the #{setting} rule for #{rule_set_description}?"
  42. end
  43. end
  44. 1 def edit_rule_submit_button
  45. submit_button class: "_rule-submit-button"
  46. end
  47. end
  48. end;end;end;end;end;
  49. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/rule_form/buttons.rb ~~

card/tmpsets/set/mod027-card-mod-rules/rule/rule_form/form_elements.rb

33.33% lines covered

33 relevant lines. 11 lines covered and 22 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Rule; module RuleForm;
  3. # Set: All rule cards (RuleForm, FormElements)
  4. #
  5. 1 module FormElements;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/rule_form/form_elements.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. #### DEPRECATED
  10. 1 def rule_set_selection
  11. wrap_with :div, class: "set-list" do
  12. [rule_set_formgroup, related_set_formgroup]
  13. end
  14. end
  15. 1 def rule_set_formgroup
  16. tag = @rule_context.rule_user_setting_name
  17. narrower = []
  18. option_list "Set" do
  19. rule_set_options.map do |set_name, state|
  20. rule_set_radio_button set_name, tag, state, narrower
  21. end
  22. end
  23. end
  24. 1 def related_set_formgroup
  25. related_sets = related_sets_in_context
  26. return "" unless related_sets&.present?
  27. tag = @rule_context.rule_user_setting_name
  28. option_list "related set" do
  29. related_rule_radios related_sets, tag
  30. end
  31. end
  32. 1 def related_sets_in_context
  33. set_context = @rule_context.rule_set_name
  34. set_context && Card.fetch(set_context).prototype.related_sets
  35. end
  36. 1 def option_list title
  37. formgroup title, input: "set", class: "col-xs-6", help: false do
  38. wrap_with :ul do
  39. wrap_each_with(:li, class: "radio") { yield }
  40. end
  41. end
  42. end
  43. 1 def related_rule_radios related_sets, tag
  44. related_sets.map do |set_name, _label|
  45. rule_name = "#{set_name}+#{tag}"
  46. state = Card.exists?(rule_name) ? :exists : nil
  47. rule_radio set_name, state do
  48. radio_button :name, rule_name
  49. end
  50. end
  51. end
  52. end
  53. end;end;end;end;end;
  54. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/rule_form/form_elements.rb ~~

card/tmpsets/set/mod027-card-mod-rules/rule/rule_form/rule_set_radio.rb

36.17% lines covered

47 relevant lines. 17 lines covered and 30 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Rule
  3. # Set: All rule cards (RuleForm)
  4. #
  5. #! no set module
  6. 1 module RuleForm;
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/rule_form/rule_set_radio.rb"; end
  8. 1 class RuleSetRadio
  9. 1 attr_reader :format
  10. 1 delegate :link_to_card, :radio_button, :wrap_with, :icon_tag,
  11. to: :format
  12. # @param state [:current, :overwritten]
  13. 1 def initialize format, set_name, tag, state
  14. @format = format
  15. @card = format.card
  16. @set_name = set_name
  17. @tag = tag
  18. @state = state
  19. end
  20. 1 def html narrower
  21. @narrower_rules = narrower
  22. rule_radio do
  23. radio_text = "#{@set_name}+#{@tag}"
  24. radio_button :name, radio_text, checked: false, warning: warning
  25. end
  26. end
  27. 1 private
  28. 1 def current?
  29. @state == :current
  30. end
  31. 1 def overwritten?
  32. @state == :overwritten
  33. end
  34. 1 def rule_radio
  35. label_classes = ["set-label", ("current-set-label" if current?)]
  36. icon = icon_tag "open_in_new", "link-muted"
  37. wrap_with :label, class: label_classes.compact.join(" ") do
  38. [yield, label, link_to_card(@set_name, icon, target: "decko_set")]
  39. end
  40. end
  41. 1 def label
  42. label = Card.fetch(@set_name).label
  43. label += " <em>#{extra_info}</em>".html_safe if extra_info
  44. label
  45. end
  46. 1 def extra_info
  47. case @state
  48. when :current
  49. "(current)"
  50. when :overwritten, :exists
  51. link_to_card "#{@set_name}+#{@card.rule_user_setting_name}", "(#{@state})",
  52. target: "_blank"
  53. end
  54. end
  55. 1 def warning
  56. if @set_name == "*all"
  57. "This rule will affect all cards! Are you sure?"
  58. else
  59. narrower_warning
  60. end
  61. end
  62. # warn user if rule change won't have a effect on the current card
  63. # because there is a narrower rule
  64. 1 def narrower_warning
  65. return unless @state.in? %i[current overwritten]
  66. @narrower_rules << Card.fetch(@set_name).uncapitalized_label
  67. return unless @state == :overwritten
  68. narrower_warning_message
  69. end
  70. 1 def narrower_warning_message
  71. plural = @narrower_rules.size > 1 ? "s" : ""
  72. "This rule will not have any effect on this card unless you delete " \
  73. "the narrower rule#{plural} for #{@narrower_rules.to_sentence}."
  74. end
  75. end
  76. end;end;end;end;
  77. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/rule_form/rule_set_radio.rb ~~

card/tmpsets/set/mod027-card-mod-rules/rule/rule_form/set_selection.rb

39.13% lines covered

23 relevant lines. 9 lines covered and 14 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Rule; module RuleForm;
  3. # Set: All rule cards (RuleForm, SetSelection)
  4. #
  5. 1 module SetSelection;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/rule_form/set_selection.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def bridge_rule_set_selection
  10. wrap_with :div, class: "set-list" do
  11. bridge_rule_set_formgroup
  12. end
  13. end
  14. 1 def bridge_rule_set_formgroup
  15. tag = @rule_context.rule_user_setting_name
  16. narrower = []
  17. bridge_option_list "Set" do
  18. rule_set_options.map do |set_name, state|
  19. RuleSetRadio.new(self, set_name, tag, state).html narrower
  20. end
  21. end
  22. end
  23. 1 def bridge_option_list title
  24. index = -1
  25. formgroup title, input: "set", class: "col-xs-6", help: false do
  26. yield.inject("") do |res, radio|
  27. index += 1
  28. # TODO
  29. if false # index.in? [2,3]
  30. wrap_with(:li, radio, class: "radio") + res
  31. else
  32. wrap_with :ul do
  33. wrap_with(:li, (radio + res), class: "radio")
  34. end
  35. end
  36. end
  37. end
  38. end
  39. 1 def rule_set_options
  40. @rule_set_options ||= @rule_context.set_options
  41. end
  42. end
  43. end;end;end;end;end;
  44. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/rule_form/set_selection.rb ~~

card/tmpsets/set/mod027-card-mod-rules/rule/rules.rb

47.46% lines covered

59 relevant lines. 28 lines covered and 31 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Rule
  3. # Set: All rule cards (Rules)
  4. #
  5. 1 module Rules;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/rules.rb"; end
  8. 1 event :save_recently_edited_settings, :integrate, on: :save, changed: %i[type content] do
  9. 10 if (recent = Card[:recent_settings])
  10. 10 recent.insert_item 0, name.right
  11. 10 attach_subcard recent
  12. end
  13. end
  14. 1 def rule_set_key
  15. rule_set_name.key
  16. end
  17. 1 def rule_set_name
  18. if is_preference?
  19. name.trunk_name.trunk_name
  20. else
  21. name.trunk_name
  22. end
  23. end
  24. 1 def rule_set_pattern_name
  25. rule_set_name.tag_name
  26. end
  27. 1 def rule_set
  28. 4 if is_preference?
  29. self[0..-3]
  30. else
  31. 4 trunk
  32. end
  33. end
  34. 1 def rule_setting
  35. right
  36. end
  37. 1 def rule_setting_name
  38. name.tag
  39. end
  40. 1 def short_help_text
  41. Card[rule_setting_name].short_help_text
  42. end
  43. 1 def rule_setting_title
  44. rule_setting_name.tr "*", ""
  45. end
  46. 1 def rule_user_setting_name
  47. if is_preference?
  48. "#{rule_user_name}+#{rule_setting_name}"
  49. else
  50. rule_setting_name
  51. end
  52. end
  53. # ~~~~~~~~~~ determine the set options to which a user can apply the rule.
  54. 1 def set_options
  55. @set_options ||= [].tap do |set_options|
  56. set_option_candidates.each do |set_name|
  57. set_options << [set_name, state_of_set(set_name)]
  58. end
  59. end
  60. end
  61. # the narrowest rule should be the one attached to the set being viewed.
  62. # So, eg, if you're looking at the '*all plus' set, you shouldn't
  63. # have the option to create rules based on arbitrary narrower sets, though
  64. # narrower sets will always apply to whatever prototype we create
  65. 1 def first_set_option_index candidates
  66. new_card? ? 0 : candidates.index { |c| c.to_name.key == rule_set_key }
  67. end
  68. 1 def set_prototype
  69. if is_preference?
  70. self[0..-3].prototype
  71. else
  72. trunk.prototype
  73. end
  74. end
  75. 1 private
  76. 1 def set_option_candidates
  77. candidates = set_prototype.set_names
  78. first = first_set_option_index candidates
  79. candidates[first..-1]
  80. end
  81. 1 def state_of_set set_name
  82. @sets_with_existing_rules ||= 0
  83. if rule_for_set? set_name
  84. @sets_with_existing_rules += 1
  85. state_of_existing_set
  86. else
  87. state_of_nonexisting_set
  88. end
  89. end
  90. 1 def state_of_existing_set
  91. @sets_with_existing_rules == 1 ? :current : :overwritten
  92. end
  93. 1 def state_of_nonexisting_set
  94. @sets_with_existing_rules == 1 ? :current : :overwritten
  95. end
  96. 1 def rule_for_set? set_name
  97. Card.exists?("#{set_name}+#{rule_user_setting_name}")
  98. end
  99. end;end;end;end;
  100. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-rules/set/rule/rules.rb ~~

card/tmpsets/set/mod027-card-mod-rules/self/script_rules.rb

100.0% lines covered

6 relevant lines. 6 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ScriptRules"
  4. #
  5. 1 module ScriptRules;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-rules/set/self/script_rules.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 Self::ScriptMods.add_item :script_rules
  10. end;end;end;end;
  11. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-rules/set/self/script_rules.rb ~~

card/tmpsets/set/mod027-card-mod-rules/type/set.rb

51.61% lines covered

62 relevant lines. 32 lines covered and 30 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Type
  3. # Set: All "Set" cards
  4. #
  5. 1 module Set;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-rules/set/type/set.rb"; end
  8. 1 include_set Type::SearchType
  9. 1 def anchor_name
  10. name.left_name
  11. end
  12. 1 def anchor
  13. Card[anchor_name]
  14. end
  15. 1 def pattern_name
  16. name.tag_name
  17. end
  18. 1 def pattern
  19. 4 tag
  20. end
  21. 1 def inheritable?
  22. junction_only? || (anchor_name&.junction? && self_set?)
  23. end
  24. 1 def self_set?
  25. pattern_name == Card::Set::Self.pattern.key
  26. end
  27. 1 def subclass_for_set
  28. 4 current_set_pattern_code = pattern.codename
  29. 8 Card.set_patterns.find { |set| set.pattern_code == current_set_pattern_code }
  30. end
  31. 1 def junction_only?
  32. @junction_only.nil? ? (@junction_only = subclass_for_set.junction_only) : @junction_only
  33. end
  34. 1 def label
  35. klass = subclass_for_set
  36. klass ? klass.label(anchor_name) : ""
  37. end
  38. 1 def uncapitalized_label
  39. label = label.to_s
  40. return label unless label[0]
  41. label[0] = label[0].downcase
  42. label
  43. end
  44. 1 def rule_cache_key_base
  45. 153 if (l = left) && (r = right)
  46. 82 "#{l.id}+#{Codename[r.id]}"
  47. else
  48. 71 Codename[id].to_s
  49. end
  50. end
  51. 1 def all_user_ids_with_rule_for setting_code
  52. 153 Card::Rule.all_user_ids_with_rule_for self, setting_code
  53. end
  54. 1 def setting_codenames_by_group
  55. result = {}
  56. Card::Setting.groups.each do |group, settings|
  57. visible_settings =
  58. settings.reject { |s| !s || !s.applies_to_cardtype(prototype.type_id) }
  59. result[group] = visible_settings.map(&:codename) unless visible_settings.empty?
  60. end
  61. result
  62. end
  63. 1 def visible_setting_codenames
  64. @visible_setting_codenames ||= visible_settings.map(&:codename)
  65. end
  66. 1 def visible_settings group=nil, cardtype_id=nil
  67. cardtype_id ||= prototype.type_id
  68. settings =
  69. (group && Card::Setting.groups[group]) || Card::Setting.groups.values.flatten.compact
  70. settings.reject do |setting|
  71. !setting || !setting.applies_to_cardtype(cardtype_id)
  72. end
  73. end
  74. 1 def broader_sets
  75. prototype.set_names[1..-1]
  76. end
  77. 1 def prototype
  78. opts = subclass_for_set.prototype_args anchor_name
  79. Card.fetch opts[:name], new: opts
  80. end
  81. 1 def prototype_default_type_id
  82. prototype_default_card.type_id
  83. end
  84. 1 def prototype_default_card
  85. prototype.rule_card(:default)
  86. end
  87. 1 def related_sets with_self=false
  88. if subclass_for_set.anchorless?
  89. prototype.related_sets with_self
  90. else
  91. left(new: {}).related_sets with_self
  92. end
  93. end
  94. end;end;end;end;
  95. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-rules/set/type/set.rb ~~

card/tmpsets/set/mod027-card-mod-rules/type/set/html_views.rb

58.62% lines covered

29 relevant lines. 17 lines covered and 12 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Type; module Set;
  3. # Set: All "Set+HtmlViews" cards (HtmlViews)
  4. #
  5. 1 module HtmlViews;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-rules/set/type/set/html_views.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 before :open do
  10. voo.hide :template_closer
  11. end
  12. 1 view :core, cache: :never do
  13. filtered_rule_list :bar_rule_list
  14. end
  15. 1 view :nest_rules, cache: :never, unknown: true, wrap: :slot do
  16. filtered_rule_list :quick_edit_rule_list, :field_related_rules, :related, mark: ""
  17. end
  18. 1 view :modal_nest_rules, cache: :never, unknown: true,
  19. wrap: { modal: { title: "Rules for nest" } } do
  20. filtered_rule_list :quick_edit_rule_list, :field_related_rules, :self
  21. end
  22. 1 view :bridge_rules_tab, cache: :never do
  23. filtered_rule_list :pill_rule_list, :common, :related, mark: ""
  24. end
  25. 1 def filtered_rule_list view, *filter_args
  26. [rules_filter(view, *filter_args),
  27. render(view)]
  28. end
  29. 1 view :set_label do
  30. wrap_with :strong, card.label, class: "set-label"
  31. end
  32. 1 Card::Setting.groups.each_key do |group_key|
  33. 7 view group_key.to_sym do
  34. next unless card.visible_settings(group_key).present?
  35. haml :group_panel, group_key: group_key
  36. end
  37. end
  38. 1 def setting_group default=:common
  39. voo&.filter&.to_sym || params[:group]&.to_sym || default
  40. end
  41. 1 view :input do
  42. "Cannot currently edit Sets" # LOCALIZE
  43. end
  44. 1 view :one_line_content, wrap: {} do
  45. ""
  46. end
  47. end
  48. end;end;end;end;end;
  49. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-rules/set/type/set/html_views.rb ~~

card/tmpsets/set/mod027-card-mod-rules/type/set/html_views/rule_lists.rb

50.0% lines covered

26 relevant lines. 13 lines covered and 13 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 5 class Card; module Set; class Type; module Set;; module HtmlViews;
  3. # Set: All "Set+HtmlViews" cards (HtmlViews, RuleLists)
  4. #
  5. 1 module RuleLists;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-rules/set/type/set/html_views/rule_lists.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :quick_edit_rule_list, cache: :never, wrap: { slot: { class: "rule-list" } } do
  10. quick_edit_rule_list setting_list_from_params(:field_related)
  11. end
  12. 1 view :bar_rule_list, cache: :never, wrap: { slot: { class: "rule-list" } } do
  13. bar_rule_list setting_list_from_params
  14. end
  15. 1 view :pill_rule_list, cache: :never, wrap: { slot: { class: "rule-list" } } do
  16. pill_rule_list setting_list_from_params
  17. end
  18. 1 def quick_edit_rule_list settings
  19. list_tag class: "nav nav-pills flex-column bridge-pills" do
  20. settings.map { |setting| rule_list_item setting, :quick_edit }
  21. end
  22. end
  23. 1 def pill_rule_list settings
  24. list_items =
  25. settings.map { |setting| rule_list_item setting, :rule_bridge_link }
  26. bridge_pills list_items
  27. end
  28. 1 def bar_rule_list settings
  29. list_items =
  30. settings.map { |setting| rule_list_item setting, :bar, hide: :full_name }
  31. list_items.join("\n").html_safe
  32. end
  33. 1 def rule_list_item setting, view, opts={}
  34. return "" unless show_view? setting
  35. rule_card = card.fetch setting, new: {}
  36. nest(rule_card, opts.merge(view: view)).html_safe
  37. end
  38. 1 def setting_list_from_params default=:common
  39. setting_list setting_group(default)
  40. end
  41. end
  42. end;end;end;end;end;end;
  43. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-rules/set/type/set/html_views/rule_lists.rb ~~

card/tmpsets/set/mod027-card-mod-rules/type/set/html_views/template.rb

63.64% lines covered

11 relevant lines. 7 lines covered and 4 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 5 class Card; module Set; class Type; module Set;; module HtmlViews;
  3. # Set: All "Set+HtmlViews" cards (HtmlViews, Template)
  4. #
  5. 1 module Template;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-rules/set/type/set/html_views/template.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :template_link, cache: :never do
  10. wrap do
  11. voo.title = parent.voo.nest_syntax if parent
  12. "{{#{link_to_template_editor}}}"
  13. end
  14. end
  15. 1 def link_to_template_editor
  16. link_to_view :modal_nest_rules, voo.title
  17. end
  18. end
  19. end;end;end;end;end;end;
  20. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-rules/set/type/set/html_views/template.rb ~~

card/tmpsets/set/mod027-card-mod-rules/type/set/rules_filter.rb

46.43% lines covered

28 relevant lines. 13 lines covered and 15 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Type; module Set;
  3. # Set: All "Set+RulesFilter" cards (RulesFilter)
  4. #
  5. 1 module RulesFilter;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-rules/set/type/set/rules_filter.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def rules_filter view, selected_setting=nil, set_options=nil, path_opts={}
  10. form_tag path(path_opts.merge(view: view)),
  11. remote: true, method: "get", role: "filter",
  12. "data-slot-selector": ".card-slot.rule-list",
  13. class: classy("nodblclick slotter form-inline slim-select2 m-2") do
  14. output [
  15. label_tag(:view, icon_tag("filter_list"), class: "mr-2"),
  16. setting_select(selected_setting),
  17. set_select(set_options)
  18. ].flatten
  19. end
  20. end
  21. 1 def set_select set_options
  22. return filter_text.html_safe unless set_options
  23. [content_tag(:span, "rules that apply to set ...", class: "mx-2 small"),
  24. set_select_tag(set_options)]
  25. end
  26. 1 def setting_select selected=nil
  27. select_tag(:group, grouped_options_for_select(setting_options, selected),
  28. class: "_submit-on-select form-control",
  29. "data-select2-id": "#{unique_id}-#{Time.now.to_i}")
  30. end
  31. 1 def filter_text
  32. wrap_with :span, class: "mx-2 small" do
  33. "rules that apply to #{_render_set_label.downcase}" # LOCALIZE
  34. end
  35. end
  36. 1 def set_select_tag set_options=:related
  37. select_tag(:mark, set_select_options(set_options),
  38. class: "_submit-on-select form-control _close-rule-overlay-on-select",
  39. "data-minimum-results-for-search": "Infinity",
  40. "data-select2-id": "#{unique_id}-#{Time.now.to_i}")
  41. end
  42. 1 def selected_set
  43. params[:set]
  44. end
  45. 1 def set_select_options set_options
  46. options =
  47. if set_options == :related
  48. related_set_options
  49. else
  50. [[card.label, card.name.url_key]]
  51. end
  52. options_for_select(options, selected_set)
  53. end
  54. 1 def related_set_options
  55. card.related_sets(true).map do |name, label|
  56. [label, name.to_name.url_key]
  57. end
  58. end
  59. end
  60. end;end;end;end;end;
  61. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-rules/set/type/set/rules_filter.rb ~~

card/tmpsets/set/mod027-card-mod-rules/type/set/setting_lists.rb

48.78% lines covered

41 relevant lines. 20 lines covered and 21 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class Type; module Set;
  3. # Set: All "Set+SettingLists" cards (SettingLists)
  4. #
  5. 1 module SettingLists;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-rules/set/type/set/setting_lists.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 SETTING_OPTIONS = [["Common", :common_rules],
  10. ["All", :all_rules],
  11. ["Field", :field_related_rules],
  12. ["Recent", :recent_rules]].freeze
  13. 1 COMMON_SETTINGS = %i[create read update delete structure default guide].freeze
  14. 1 FIELD_SETTINGS = %i[default help].freeze
  15. 1 def setting_options
  16. [["Categories", SETTING_OPTIONS],
  17. ["Groups", Card::Setting.group_names.keys],
  18. ["Single rules", card.visible_setting_codenames]]
  19. end
  20. 1 def field_settings
  21. %i[default help input_type content_options content_option_view]
  22. end
  23. # @param val setting category, setting group or single setting
  24. 1 def setting_list val
  25. category_setting_list(val) || group_setting_list(val) || [val]
  26. end
  27. 1 def group_setting_list group
  28. card.visible_settings(group).map(&:codename) if Card::Setting.groups[group]
  29. end
  30. 1 def category_setting_list cat
  31. case cat
  32. when :all, :all_rules
  33. card.visible_setting_codenames.sort
  34. when :recent, :recent_rules
  35. recent_settings
  36. when :common, :common_rules
  37. card.visible_setting_codenames & COMMON_SETTINGS
  38. when :field_related, :field_related_rules
  39. field_related_settings
  40. when :nest_editor_field_related
  41. nest_editor_field_related_settings
  42. end
  43. end
  44. 1 def nest_editor_field_related_settings
  45. field_settings
  46. # & card.visible_settings(nil, card.prototype_default_type_id).map(&:codename)
  47. end
  48. 1 def field_related_settings
  49. field_settings # card.visible_setting_codenames &
  50. end
  51. 1 def recent_settings
  52. recent_settings = Card[:recent_settings].item_cards.map(&:codename)
  53. recent_settings.map(&:to_sym) & card.visible_setting_codenames
  54. end
  55. 1 view :all_rules_list do
  56. pill_rule_list card.visible_setting_codenames.sort
  57. end
  58. 1 view :recent_rules_list do
  59. recent_settings = Card[:recent_settings].item_cards.map(&:codename)
  60. settings = recent_settings.map(&:to_sym) & card.visible_setting_codenames
  61. pill_rule_list settings
  62. end
  63. 1 view :common_rules_list do
  64. settings = card.visible_setting_codenames & COMMON_SETTINGS # "&" = set intersection
  65. pill_rule_list settings
  66. end
  67. 1 view :field_related_rules_list do
  68. pill_rule_list field_related_settings
  69. end
  70. end
  71. end;end;end;end;end;
  72. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-rules/set/type/set/setting_lists.rb ~~

card/tmpsets/set/mod028-card-mod-tinymce_editor/all/reference_editor.rb

52.38% lines covered

21 relevant lines. 11 lines covered and 10 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (ReferenceEditor)
  4. #
  5. # shared helper methods for link editor and nest editor
  6. 1 module ReferenceEditor;
  7. 1 extend Card::Set
  8. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-tinymce_editor/set/all/reference_editor.rb"; end
  9. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  10. 1 def tinymce_id
  11. params[:tinymce_id]
  12. end
  13. 1 def tm_param key
  14. params[:"tm_snippet_#{key}"]
  15. end
  16. 1 def modal_tm_snippet_editor?
  17. @tm_snippet_editor_mode != :overlay
  18. end
  19. 1 private
  20. 1 def apply_tm_snippet_data snippet
  21. { "data-tinymce-id": tinymce_id }.tap do |data|
  22. apply_tm_snippet_var(data, :start) { tm_param :start }
  23. apply_tm_snippet_var(data, :size, :raw) { snippet.raw.size }
  24. data["data-dismiss"] = "modal" if modal_tm_snippet_editor?
  25. data["data-index"] = params["index"] if params["index"].present?
  26. end
  27. end
  28. 1 def apply_tm_snippet_var data, varname, paramname=nil
  29. return unless tm_param(paramname || varname).present?
  30. data[:"data-tm-snippet-#{varname}"] = yield
  31. end
  32. end
  33. end;end;end;end;
  34. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-tinymce_editor/set/all/reference_editor.rb ~~

card/tmpsets/set/mod028-card-mod-tinymce_editor/all/reference_editor/link_editor.rb

57.89% lines covered

19 relevant lines. 11 lines covered and 8 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module ReferenceEditor;
  3. # Set: All cards (ReferenceEditor, LinkEditor)
  4. #
  5. 1 module LinkEditor;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-tinymce_editor/set/all/reference_editor/link_editor.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :link_editor, cache: :never, unknown: true,
  10. wrap: {
  11. slot: { class: "_overlay d0-card-overlay card nodblclick" }
  12. } do
  13. link_editor :overlay
  14. end
  15. 1 view :modal_link_editor, cache: :never, unknown: true,
  16. wrap: { slot: { class: "nodblclick" } } do
  17. modal_link_editor
  18. end
  19. 1 def link_editor editor_mode
  20. @tm_snippet_editor_mode = editor_mode
  21. haml :reference_editor, ref_type: :link, editor_mode: @tm_snippet_editor_mode,
  22. apply_opts: link_apply_opts, snippet: link_snippet
  23. end
  24. 1 def modal_link_editor
  25. wrap_with :modal do
  26. link_editor :modal
  27. end
  28. end
  29. 1 def link_snippet
  30. @link_snippet ||= LinkParser.new params[:tm_snippet_raw]
  31. end
  32. 1 def link_apply_opts
  33. apply_tm_snippet_data link_snippet
  34. end
  35. end
  36. end;end;end;end;end;
  37. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-tinymce_editor/set/all/reference_editor/link_editor.rb ~~

card/tmpsets/set/mod028-card-mod-tinymce_editor/all/reference_editor/link_editor/link_parser.rb

52.38% lines covered

21 relevant lines. 11 lines covered and 10 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module ReferenceEditor;
  3. # Set: All cards (ReferenceEditor, LinkEditor)
  4. #
  5. #! no set module
  6. 1 module LinkEditor;
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-tinymce_editor/set/all/reference_editor/link_editor/link_parser.rb"; end
  8. # Extracts all information needed to generate the link editor form
  9. # from a link syntax string
  10. 1 class LinkParser
  11. 1 attr_reader :name, :options, :field, :raw
  12. 1 def self.new link_string
  13. return super if link_string.is_a? String
  14. OpenStruct.new(name: "", options: {}, raw: "[[ ]]")
  15. end
  16. 1 def initialize link_string
  17. @raw = link_string
  18. link = Card::Content::Chunk::Link.new link_string, nil
  19. init_name link.name
  20. @options = link.options
  21. end
  22. 1 def title
  23. @options && @options[:title]
  24. end
  25. 1 def field?
  26. @field
  27. end
  28. 1 private
  29. 1 def init_name name
  30. @field = name.to_name.simple_relative?
  31. @name = @field ? name.to_s[1..-1] : name
  32. end
  33. end
  34. end;end;end;end;end;
  35. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-tinymce_editor/set/all/reference_editor/link_editor/link_parser.rb ~~

card/tmpsets/set/mod028-card-mod-tinymce_editor/all/reference_editor/nest_editor.rb

33.33% lines covered

87 relevant lines. 29 lines covered and 58 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module ReferenceEditor;
  3. # Set: All cards (ReferenceEditor, NestEditor)
  4. #
  5. 1 module NestEditor;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-tinymce_editor/set/all/reference_editor/nest_editor.rb"; end
  8. 1 def left_type_for_nest_editor_set_selection
  9. type_name
  10. end
  11. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  12. # Card::View::Options.shark_keys - %i[nest_syntax nest_name items cache]
  13. # TODO: connect to Card::View::Options
  14. # (that way a mod can add an option that becomes available to nests)
  15. 1 view :nest_editor, cache: :never, unknown: true,
  16. wrap: {
  17. slot: { class: "_overlay d0-card-overlay card nodblclick" }
  18. } do
  19. nest_editor :overlay
  20. end
  21. 1 view :modal_nest_editor, cache: :never, unknown: true,
  22. wrap: { slot: { class: "nodblclick" } } do
  23. modal_nest_editor
  24. end
  25. 1 view :nest_content, perms: :create, cache: :never, unknown: true, wrap: :slot do
  26. if card.known?
  27. known_nest_content
  28. else
  29. unknown_nest_content
  30. end
  31. end
  32. 1 def nest_editor editor_mode
  33. @tm_snippet_editor_mode = editor_mode
  34. voo.hide :content_tab unless show_content_tab?
  35. haml :reference_editor, ref_type: :nest, editor_mode: @tm_snippet_editor_mode,
  36. apply_opts: nest_apply_opts,
  37. snippet: nest_snippet
  38. end
  39. 1 def nest_editor_tabs
  40. tab_hash = {}
  41. tab_hash[:content] = nest_content_tab if voo.show? :content_tab
  42. tab_hash.merge! options: haml(:_options, snippet: nest_snippet),
  43. rules: nest_rules_tab,
  44. help: haml(:_help)
  45. tabs tab_hash, default_active_tab
  46. end
  47. 1 def show_content_tab?
  48. !card.is_structure?
  49. end
  50. 1 def default_active_tab
  51. voo.show?(:content_tab) ? :content : :options
  52. end
  53. 1 def nest_content_tab
  54. name_dependent_slot do
  55. @nest_content_tab || nest(card.name.field(nest_snippet.name),
  56. view: :nest_content, hide: :guide)
  57. end
  58. end
  59. 1 def nest_rules_tab
  60. name_dependent_slot do
  61. nest(set_name_for_nest_rules, view: :nest_rules)
  62. end
  63. end
  64. 1 def name_dependent_slot
  65. result = [empty_nest_name_alert(nest_snippet.name.blank?)]
  66. result <<
  67. if nest_snippet.name.blank?
  68. content_tag :div, "", class: "card-slot" # placeholder
  69. else
  70. yield
  71. end
  72. result
  73. end
  74. 1 def empty_nest_name_alert show
  75. alert :warning, false, false,
  76. class: "mb-0 _empty-nest-name-alert #{'d-none' unless show}" do
  77. "nest name required" # LOCALIZE
  78. end
  79. end
  80. 1 def modal_nest_editor
  81. wrap_with :modal do
  82. nest_editor :modal
  83. end
  84. end
  85. 1 def nest_snippet
  86. @nest_snippet ||=
  87. Card::Reference::NestParser.new params[:tm_snippet_raw],
  88. default_nest_view, default_item_view
  89. end
  90. 1 def set_name_for_nest_rules
  91. nest_name = nest_snippet.name
  92. if (type_name = card.left_type_for_nest_editor_set_selection)
  93. [type_name, nest_name, :type_plus_right]
  94. else
  95. [nest_name, :right]
  96. end
  97. end
  98. 1 def default_nest_editor_item_options
  99. [[:view, default_item_view]]
  100. end
  101. 1 def nest_option_name_select selected=nil, level=0
  102. classes = "form-control form-control-sm _nest-option-name"
  103. classes += " _new-row" unless selected
  104. select_tag "nest_option_name_#{unique_id}",
  105. nest_option_name_select_options(selected, level),
  106. class: classes, id: nil
  107. # id: nil ensures that select2 generates its own unique identifier
  108. # that ensures that we can clone this tag without breaking select2
  109. end
  110. 1 def nest_option_name_select_options selected, level
  111. options = selected ? [] : ["--"]
  112. options += Card::Reference::NestParser::NEST_OPTIONS
  113. options_for_select(
  114. options, disabled: nest_option_name_disabled(selected, level),
  115. selected: selected
  116. )
  117. end
  118. 1 def nest_option_name_disabled selected, level
  119. disabled = nest_option_name_disabled_options level
  120. disabled = disabled&.map(&:first)
  121. disabled&.delete selected if selected
  122. disabled
  123. end
  124. 1 def nest_option_name_disabled_options level
  125. if level == 0
  126. nest_snippet.options
  127. else
  128. nest_snippet.item_options[level - 1] || default_nest_editor_item_options
  129. end
  130. end
  131. 1 def nest_apply_opts
  132. apply_tm_snippet_data nest_snippet
  133. end
  134. 1 def nest_option_value_select value=nil
  135. # select_tag "nest_option_value_#{unique_id}"
  136. text_field_tag "value", value,
  137. class: "_nest-option-value form-control form-control-sm",
  138. disabled: !value,
  139. id: nil
  140. end
  141. 1 def known_nest_content
  142. voo.hide! :cancel_button
  143. add_name_context
  144. with_nest_mode :edit do
  145. frame do
  146. [
  147. render_edit_inline
  148. ]
  149. end
  150. end
  151. end
  152. 1 def unknown_nest_content
  153. voo.hide! :guide
  154. voo.show! :new_type_formgroup
  155. new_view_frame_and_form buttons: new_image_buttons,
  156. success: { tinymce_id: Env.params[:tinymce_id] }
  157. end
  158. end
  159. end;end;end;end;end;
  160. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-tinymce_editor/set/all/reference_editor/nest_editor.rb ~~

card/tmpsets/set/mod028-card-mod-tinymce_editor/all/reference_editor/nest_image.rb

41.67% lines covered

36 relevant lines. 15 lines covered and 21 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 4 class Card; module Set; class All; module ReferenceEditor;
  3. # Set: All cards (ReferenceEditor, NestImage)
  4. #
  5. 1 module NestImage;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-tinymce_editor/set/all/reference_editor/nest_image.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :nest_image, unknown: true, cache: :never,
  10. wrap: {
  11. slot: { class: "_overlay d0-card-overlay card nodblclick" }
  12. } do
  13. nest_image_editor :overlay
  14. end
  15. 1 view :modal_nest_image, unknown: true, cache: :never,
  16. wrap: { slot: { class: "nodblclick" } } do
  17. nest_image_editor :modal
  18. end
  19. 1 view :new_image, perms: :create, unknown: true, cache: :never do
  20. new_view_frame_and_form new_image_form_opts
  21. end
  22. 1 def nest_image_editor editor_mode
  23. adapt_reference_editor_for_images
  24. nest_editor editor_mode
  25. end
  26. 1 def adapt_reference_editor_for_images
  27. nest_name = card.autoname(card.name.field("image01"))
  28. voo.show! :content_tab
  29. @nest_content_tab = nest(nest_name, view: :new_image, type: :image, hide: :guide)
  30. image_name = nest_name.to_name.right
  31. @nest_snippet = Card::Reference::NestParser.new_image image_name
  32. end
  33. 1 def new_image_form_opts
  34. { buttons: new_image_buttons,
  35. success: { tinymce_id: Env.params[:tinymce_id],
  36. view: :open } }
  37. end
  38. 1 def new_image_buttons
  39. button_formgroup do
  40. [standard_save_button(no_origin_update: true, class: "_change-create-to-update")]
  41. end
  42. end
  43. end
  44. 2 module JsFormat; module_parent.send :register_set_format, Card::Format::JsFormat, self; extend Card::Set::AbstractFormat
  45. 1 view :change_create_to_update, unknown: true do
  46. tm_id = if Env.params[:tinymce_id].present?
  47. "\"#{Env.params[:tinymce_id]}\""
  48. else
  49. '$(".tinymce-textarea").attr("id")'
  50. end
  51. <<-JAVASCRIPT.strip_heredoc
  52. nest.changeCreateToUpdate(#{tm_id});
  53. JAVASCRIPT
  54. end
  55. 1 view :open_nest_editor, unknown: true do
  56. tm_id = if Env.params[:tinymce_id].present?
  57. "\"#{Env.params[:tinymce_id]}\""
  58. else
  59. '$(".tinymce-textarea").attr("id")'
  60. end
  61. <<-JAVASCRIPT.strip_heredoc
  62. tm = tinymce.get(#{tm_id});
  63. nest.insertNest(tm, "{{+#{card.name.tag}|view: content; size: medium}}");
  64. JAVASCRIPT
  65. end
  66. end
  67. end;end;end;end;end;
  68. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-tinymce_editor/set/all/reference_editor/nest_image.rb ~~

card/tmpsets/set/mod028-card-mod-tinymce_editor/all/tinymce_editor.rb

100.0% lines covered

7 relevant lines. 7 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (TinymceEditor)
  4. #
  5. 1 module TinymceEditor;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-tinymce_editor/set/all/tinymce_editor.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 def tinymce_editor_input
  10. 7 text_area :content, rows: 3, class: "tinymce-textarea d0-card-content",
  11. id: unique_id
  12. end
  13. end
  14. end;end;end;end;
  15. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-tinymce_editor/set/all/tinymce_editor.rb ~~

card/tmpsets/set/mod028-card-mod-tinymce_editor/self/script_tinymce.rb

100.0% lines covered

7 relevant lines. 7 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ScriptTinymce"
  4. #
  5. 1 module ScriptTinymce;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-tinymce_editor/set/self/script_tinymce.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 Self::ScriptMods.add_item :script_tinymce
  10. 1 Self::InputOptions.add_to_basket :options, "tinymce editor"
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-tinymce_editor/set/self/script_tinymce.rb ~~

card/tmpsets/set/mod028-card-mod-tinymce_editor/self/script_tinymce_config.rb

100.0% lines covered

7 relevant lines. 7 lines covered and 0 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "ScriptTinymceConfig"
  4. #
  5. 1 module ScriptTinymceConfig;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-tinymce_editor/set/self/script_tinymce_config.rb"; end
  8. 1 include_set Abstract::CodeFile
  9. 1 Self::ScriptEditors.add_item :script_tinymce_config
  10. 1 All::Head::HtmlFormat.add_to_basket :mod_js_config, [:tiny_mce, "setTinyMCEConfig"]
  11. end;end;end;end;
  12. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-tinymce_editor/set/self/script_tinymce_config.rb ~~

card/tmpsets/set/mod028-card-mod-tinymce_editor/self/tiny_mce.rb

83.33% lines covered

6 relevant lines. 5 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Self
  3. # Set: The card "TinyMce"
  4. #
  5. 1 module TinyMce;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-tinymce_editor/set/self/tiny_mce.rb"; end
  8. 1 def raw_help_text
  9. <<-TEXT
  10. Configure [[http://tinymce.com|TinyMCE]], Decko's default
  11. [[http://en.wikipedia.org/wiki/Wysiwyg|wysiwyg]] editor.
  12. [[http://decko.org/TinyMCE|more]]
  13. TEXT
  14. end
  15. end;end;end;end;
  16. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-tinymce_editor/set/self/tiny_mce.rb ~~

card/tmpsets/set/mod030-card-mod-monkey/all/event_viz.rb

33.33% lines covered

36 relevant lines. 12 lines covered and 24 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (EventViz)
  4. #
  5. # the events method is a developer's tool for visualizing the event order
  6. # for a given card.
  7. # For example, from a console you might run
  8. #
  9. # puts mycard.events :update
  10. #
  11. # to see the order of events that will be executed on mycard.
  12. 1 module EventViz;
  13. 1 extend Card::Set
  14. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-monkey/set/all/event_viz.rb"; end
  15. # The indention and arrows (^v) indicate event dependencies.
  16. #
  17. # Note: as of yet, the functionality is a bit rough. It does not display events
  18. # that are called directly from within other events,
  19. # and certain event requirements (like the presence of an 'act') may
  20. # prevent events from showing up in the tree.
  21. 1 def events action
  22. @action = action
  23. events = Director::Stages::STAGES.map { |stage| events_tree "#{stage}_stage" }
  24. @action = nil
  25. print_events events
  26. end
  27. 1 def events_tree filt
  28. try("_#{filt}_callbacks")&.each_with_object({ name: filt }) do |callback, hash|
  29. events_branch hash, callback.kind, callback.filter if callback.applies? self
  30. end
  31. end
  32. 1 private
  33. 1 def print_events events, prefix="", depth=0
  34. depth += 1
  35. space = " " * (depth * 2)
  36. text = ""
  37. events.each do |event|
  38. text += print_event_pre event, depth, space
  39. text += print_event_main event, prefix
  40. text += print_event_post event, depth, space
  41. end
  42. text
  43. end
  44. 1 def print_event_pre event, depth, space
  45. if event[:before]
  46. print_events event[:before], space + "v ", depth
  47. elsif event[:around]
  48. print_events event[:around], space + "vv ", depth
  49. else
  50. ""
  51. end
  52. end
  53. 1 def print_event_main event, prefix
  54. "#{prefix}#{event[:name]}\n"
  55. end
  56. 1 def print_event_post event, depth, space
  57. return "" unless event[:after]
  58. print_events event[:after], space + "^ ", depth
  59. end
  60. 1 def events_branch hash, kind, filter
  61. hash[kind] ||= []
  62. hash[kind] << events_tree(filter)
  63. end
  64. end;end;end;end;
  65. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-monkey/set/all/event_viz.rb ~~

card/tmpsets/set/mod030-card-mod-monkey/all/view_viz.rb

38.89% lines covered

18 relevant lines. 7 lines covered and 11 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class All
  3. # Set: All cards (ViewViz)
  4. #
  5. 1 module ViewViz;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-monkey/set/all/view_viz.rb"; end
  8. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  9. 1 view :views_by_format do
  10. format_views =
  11. self.class.ancestors.each_with_object({}) do |format_class, hash|
  12. views =
  13. format_class.instance_methods.map do |method|
  14. next unless method.to_s =~ /^_view_(.+)$/
  15. Regexp.last_match(1)
  16. end.compact
  17. next unless views.present?
  18. format_class.name =~ /^Card(::Set)?::(.+?)$/ #::(\w+Format)
  19. hash[Regexp.last_match(2)] = views
  20. end
  21. accordion_group format_views
  22. end
  23. 1 view :views_by_name do
  24. views = methods.map do |method|
  25. Regexp.last_match(1) if method.to_s.match?(/^_view_(.+)$/)
  26. end.compact.sort
  27. list_group views
  28. end
  29. end
  30. end;end;end;end;
  31. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-monkey/set/all/view_viz.rb ~~

card/tmpsets/set/mod030-card-mod-monkey/right/debug.rb

30.61% lines covered

49 relevant lines. 15 lines covered and 34 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. 3 class Card; module Set; class Right
  3. # Set: All "+Debug" cards
  4. #
  5. 1 module Debug;
  6. 1 extend Card::Set
  7. 1 def self.source_location; "/Users/ezl5238/dev/decko/gem/card-mod-monkey/set/right/debug.rb"; end
  8. 1 def virtual?
  9. new?
  10. end
  11. 2 module HtmlFormat; module_parent.send :register_set_format, Card::Format::HtmlFormat, self; extend Card::Set::AbstractFormat
  12. 1 view :core do
  13. core_section_config(card.left).map do |item|
  14. section(*item)
  15. end
  16. end
  17. 1 def core_section_config subject
  18. [["Sets", tabs("set modules" => set_modules_accordion(subject),
  19. "all modules" => singleton_modules_list(subject),
  20. "patterns" => set_patterns_breadcrumb(subject))],
  21. ["Views", tabs("by format" => subformat(subject)._render_views_by_format,
  22. "by name" => subformat(subject)._render_views_by_name)],
  23. ["Events", tabs(create: "<pre>#{subject.events(:create)}</pre>",
  24. update: "<pre>#{subject.events(:update)}</pre>",
  25. delete: "<pre>#{subject.events(:delete)}</pre>")],
  26. ["Cache/DB Comparison", cache_comparison_table(subject)]]
  27. end
  28. # rubocop:disable AccessorMethodName
  29. 1 def set_modules_accordion subject
  30. sets = subject.set_modules.each_with_object({}) do |sm, hash|
  31. ans = sm.ancestors
  32. ans.shift
  33. hash[sm.to_s] = ans
  34. end
  35. accordion_group sets
  36. end
  37. 1 def set_patterns_breadcrumb subject
  38. links = subject.patterns.reverse.map { |pattern| link_to_card pattern.to_s }
  39. breadcrumb links
  40. end
  41. # rubocop:enable AccessorMethodName
  42. 1 def singleton_modules_list subject
  43. all_mods = subject.singleton_class.ancestors.map(&:to_s)
  44. all_mods.shift
  45. list_group all_mods
  46. end
  47. 1 def cache_comparison_table subject
  48. cache_card = Card.fetch(subject.key)
  49. db_card = Card.find_by_key(subject.key)
  50. return unless cache_card && db_card
  51. table(
  52. %i[name updated_at updater_id content inspect].map do |field|
  53. [field.to_s,
  54. h(cache_card.send(field)),
  55. h(db_card.send(field))]
  56. end,
  57. header: ["Field", "Cache Val", "Database Val"]
  58. )
  59. end
  60. 1 def section title, content
  61. %(
  62. <h2>#{title}</h2>
  63. #{content}
  64. )
  65. end
  66. 1 def class_locations klass
  67. methods = defined_methods(klass)
  68. file_groups = methods.group_by { |sl| sl[0] }
  69. file_counts = file_groups.map do |file, sls|
  70. lines = sls.map { |sl| sl[1] }
  71. count = lines.size
  72. line = lines.min
  73. { file: file, count: count, line: line }
  74. end
  75. file_counts.sort_by! { |fc| fc[:count] }
  76. file_counts.map { |fc| [fc[:file], fc[:line]] }
  77. end
  78. 1 def defined_methods klass
  79. methods =
  80. klass.methods(false).map { |m| klass.method(m) } +
  81. klass.instance_methods(false).map { |m| klass.instance_method(m) }
  82. methods.map!(&:source_location)
  83. methods.compact!
  84. methods
  85. end
  86. end
  87. end;end;end;end;
  88. # ~~ generated from /Users/ezl5238/dev/decko/gem/card-mod-monkey/set/right/debug.rb ~~

card/tmpsets/set_pattern/100-all.rb

81.82% lines covered

11 relevant lines. 9 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. # Set Pattern: All
  3. #
  4. 1 class Card::Set::All < Card::Set::Pattern::Base
  5. 1 extend Card::Set::Pattern::Helper
  6. 1 cattr_accessor :options
  7. 1 class << self
  8. 1 def label _name
  9. 140 "All cards"
  10. end
  11. 1 def short_label _name
  12. "everything"
  13. end
  14. 1 def prototype_args _anchor
  15. {}
  16. end
  17. end
  18. 1 register "All".underscore.to_sym, (options || {})
  19. end
  20. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set_pattern/01_all.rb ~~

card/tmpsets/set_pattern/101-all_plus.rb

75.0% lines covered

12 relevant lines. 9 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. # Set Pattern: AllPlus
  3. #
  4. 1 class Card::Set::AllPlus < Card::Set::Pattern::Base
  5. 1 extend Card::Set::Pattern::Helper
  6. 1 cattr_accessor :options
  7. 1 class << self
  8. 1 @@options = { junction_only: true }
  9. 1 def label _name
  10. 'All "+" cards'
  11. end
  12. 1 def short_label _name
  13. 'all "+" cards'
  14. end
  15. 1 def prototype_args _anchor
  16. { name: "+" }
  17. end
  18. end
  19. 1 register "AllPlus".underscore.to_sym, (options || {})
  20. end
  21. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set_pattern/02_all_plus.rb ~~

card/tmpsets/set_pattern/102-type.rb

85.0% lines covered

20 relevant lines. 17 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. # Set Pattern: Type
  3. #
  4. 1 class Card::Set::Type < Card::Set::Pattern::Base
  5. 1 extend Card::Set::Pattern::Helper
  6. 1 cattr_accessor :options
  7. 1 class << self
  8. 1 load "card/set/type.rb" # "load" not "require" so pattern reloads properly
  9. 1 def label name
  10. 53 %(All "#{name}" cards)
  11. end
  12. 1 def short_label name
  13. %(all "#{name}s")
  14. end
  15. 1 def generic_label
  16. "cards of a given type"
  17. end
  18. 1 def prototype_args anchor
  19. { type: anchor }
  20. end
  21. 1 def pattern_applies? card
  22. 4940 !!card.type_id
  23. end
  24. 1 def anchor_name card
  25. 4406 card.type_name
  26. end
  27. 1 def anchor_id card
  28. 4406 card.type_id
  29. end
  30. end
  31. 1 register "Type".underscore.to_sym, (options || {})
  32. end
  33. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set_pattern/03_type.rb ~~

card/tmpsets/set_pattern/103-star.rb

76.92% lines covered

13 relevant lines. 10 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. # Set Pattern: Star
  3. #
  4. 1 class Card::Set::Star < Card::Set::Pattern::Base
  5. 1 extend Card::Set::Pattern::Helper
  6. 1 cattr_accessor :options
  7. 1 class << self
  8. 1 def label _name
  9. 'All "*" cards'
  10. end
  11. 1 def short_label _name
  12. 'all "*" cards'
  13. end
  14. 1 def prototype_args _anchor
  15. { name: "*dummy" }
  16. end
  17. 1 def pattern_applies? card
  18. 4940 card.name.star?
  19. end
  20. end
  21. 1 register "Star".underscore.to_sym, (options || {})
  22. end
  23. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set_pattern/04_star.rb ~~

card/tmpsets/set_pattern/104-rstar.rb

85.71% lines covered

14 relevant lines. 12 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. # Set Pattern: Rstar
  3. #
  4. 1 class Card::Set::Rstar < Card::Set::Pattern::Base
  5. 1 extend Card::Set::Pattern::Helper
  6. 1 cattr_accessor :options
  7. 1 class << self
  8. 1 @@options = { junction_only: true }
  9. 1 def label _name
  10. 1 'All "+*" cards'
  11. end
  12. 1 def short_label _name
  13. 'all "+*" cards'
  14. end
  15. 1 def prototype_args _anchor
  16. { name: "*dummy+*dummy" }
  17. end
  18. 1 def pattern_applies? card
  19. 4940 card.name.rstar?
  20. end
  21. end
  22. 1 register "Rstar".underscore.to_sym, (options || {})
  23. end
  24. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set_pattern/05_rstar.rb ~~

card/tmpsets/set_pattern/105-rule.rb

85.71% lines covered

14 relevant lines. 12 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. # Set Pattern: Rule
  3. #
  4. 1 class Card::Set::Rule < Card::Set::Pattern::Base
  5. 1 extend Card::Set::Pattern::Helper
  6. 1 cattr_accessor :options
  7. 1 class << self
  8. 1 @@options = { junction_only: true }
  9. 1 def label _name
  10. 11 "All rule cards"
  11. end
  12. 1 def short_label _name
  13. "all rule cards"
  14. end
  15. 1 def prototype_args _anchor
  16. { name: "*all+*create" }
  17. end
  18. 1 def pattern_applies? card
  19. 4940 card.is_rule?
  20. end
  21. end
  22. 1 register "Rule".underscore.to_sym, (options || {})
  23. end
  24. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set_pattern/06_rule.rb ~~

card/tmpsets/set_pattern/106-right.rb

81.25% lines covered

16 relevant lines. 13 lines covered and 3 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. # Set Pattern: Right
  3. #
  4. 1 class Card::Set::Right < Card::Set::Pattern::Base
  5. 1 extend Card::Set::Pattern::Helper
  6. 1 cattr_accessor :options
  7. 1 class << self
  8. @@options = {
  9. 1 junction_only: true,
  10. assigns_type: true
  11. }
  12. 1 def label name
  13. 60 %(All "+#{name}" cards)
  14. end
  15. 1 def short_label name
  16. %(all "+#{name}s")
  17. end
  18. 1 def generic_label
  19. "given field cards"
  20. end
  21. 1 def prototype_args anchor
  22. { name: "*dummy+#{anchor}" }
  23. end
  24. 1 def anchor_name card
  25. 1657 card.name.tag
  26. end
  27. end
  28. 1 register "Right".underscore.to_sym, (options || {})
  29. end
  30. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set_pattern/07_right.rb ~~

card/tmpsets/set_pattern/107-type_plus_right.rb

77.78% lines covered

18 relevant lines. 14 lines covered and 4 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. # Set Pattern: TypePlusRight
  3. #
  4. # Patterned field names on a specific type
  5. 1 class Card::Set::TypePlusRight < Card::Set::Pattern::Base
  6. 1 extend Card::Set::Pattern::Helper
  7. 1 cattr_accessor :options
  8. 1 class << self
  9. @@options = {
  10. 1 junction_only: true,
  11. assigns_type: true,
  12. anchor_parts_count: 2
  13. }
  14. 1 def label name
  15. 4 name = name.to_name
  16. 4 %(All "+#{name.tag}" cards on "#{name.left}" cards)
  17. end
  18. 1 def short_label name
  19. name = name.to_name
  20. %(all "+#{name.tag}" on "#{name.left}s")
  21. end
  22. 1 def generic_label
  23. "given field cards on a given type"
  24. end
  25. 1 def prototype_args anchor
  26. {
  27. name: "+#{anchor.tag}",
  28. supercard: Card.new(name: "*dummy", type: anchor.trunk_name)
  29. }
  30. end
  31. 1 def anchor_name card
  32. 1657 "#{left_type(card)}+#{card.name.tag}"
  33. end
  34. end
  35. 1 register "TypePlusRight".underscore.to_sym, (options || {})
  36. end
  37. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set_pattern/08_type_plus_right.rb ~~

card/tmpsets/set_pattern/108-self.rb

88.24% lines covered

17 relevant lines. 15 lines covered and 2 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. # Set Pattern: Self
  3. #
  4. 1 class Card::Set::Self < Card::Set::Pattern::Base
  5. 1 extend Card::Set::Pattern::Helper
  6. 1 cattr_accessor :options
  7. 1 class << self
  8. 1 def label name
  9. 102 %(The card "#{name}")
  10. end
  11. 1 def short_label name
  12. 4 name
  13. end
  14. 1 def generic_label
  15. "a single card"
  16. end
  17. 1 def prototype_args anchor
  18. { name: anchor }
  19. end
  20. 1 def anchor_name card
  21. 4940 card.name
  22. end
  23. 1 def anchor_id card
  24. 4940 card.id
  25. end
  26. end
  27. 1 register "Self".underscore.to_sym, (options || {})
  28. end
  29. # ~~ generated from /Users/ezl5238/dev/decko/gem/card/mod/core/set_pattern/09_self.rb ~~

decko/lib/decko/response.rb

90.91% lines covered

88 relevant lines. 80 lines covered and 8 lines missed.
    
  1. 1 module Decko
  2. # methods for managing decko responses
  3. 1 module Response
  4. 1 def response_format
  5. 33 @response_format ||= format_name_from_params
  6. end
  7. 1 private
  8. 1 def respond format, result, status
  9. 33 if status.in? [302, 303]
  10. 1 hard_redirect result
  11. 32 elsif format.is_a?(Card::Format::FileFormat) && status == 200
  12. 1 send_file(*result)
  13. else
  14. 31 render_response result.to_s.html_safe, status, format.mime_type
  15. end
  16. end
  17. 1 def render_response body, status, content_type
  18. 31 render body: body, status: status, content_type: content_type
  19. end
  20. 1 def redirect_cud_success success
  21. 13 redirect_type = success.redirect || default_cud_success_redirect_type
  22. 13 if redirect_type.to_s == "soft"
  23. 7 success.target ||= self
  24. 7 soft_redirect success
  25. else
  26. 6 hard_redirect success.to_url, 303
  27. end
  28. end
  29. 1 def default_cud_success_redirect_type
  30. 10 Card::Env.ajax? ? "soft" : "hard"
  31. end
  32. # return a redirect response
  33. 1 def hard_redirect url, status=302
  34. 8 url = card_url url # make sure we have absolute url
  35. 8 if Card::Env.ajax?
  36. # lets client reset window location
  37. # (not just receive redirected response)
  38. # formerly used 303 response, but that gave IE the fits
  39. render json: { redirect: url }
  40. else
  41. 8 redirect_to url, status: status
  42. end
  43. end
  44. # return a standard GET response directly.
  45. # Used in AJAX situations where PRG pattern is unwieldy
  46. 1 def soft_redirect success
  47. # Card::Cache.renew
  48. 7 @card = success.target
  49. 7 require_card_for_soft_redirect!
  50. 7 self.params = Card::Env[:params] = soft_redirect_params
  51. 7 load_action
  52. 7 show
  53. end
  54. 1 def reload
  55. render json: { reload: true }
  56. end
  57. 1 def soft_redirect_params
  58. 7 new_params = params.clone
  59. 7 new_params.delete :card
  60. 7 new_params.delete :action
  61. 7 new_params.merge Card::Env.success.params
  62. end
  63. 1 def require_card_for_soft_redirect!
  64. 7 return if card.is_a? Card
  65. raise Card::Error, "tried to do soft redirect without a card"
  66. end
  67. # (obviously) deprecated
  68. 1 def send_deprecated_asset
  69. 2 filename = [params[:mark], params[:format]].compact.join(".")
  70. 2 send_file asset_file_path(filename), x_sendfile: true
  71. end
  72. 1 def asset_file_path filename
  73. 2 path = Decko::Engine.paths["gem-assets"].existent.first
  74. 2 path = File.join path, filename
  75. 2 validate_path filename, path
  76. 1 path
  77. end
  78. 1 def validate_path filename, path
  79. # for security, block relative paths
  80. 2 raise Card::Error::BadAddress if filename.include?("../") || !::File.exist?(path)
  81. end
  82. # TODO: everything below should go in a separate file
  83. # below is about beginning (initialization). above is about end (response)
  84. # Both this file and that would make sense as submodules of CardController
  85. 1 def load_format
  86. 33 request.format = :html if implicit_html?
  87. 33 card.format response_format
  88. end
  89. 1 def implicit_html?
  90. 33 (Card::Env.ajax? && !params[:format]) || request.format.to_s == "*/*"
  91. end
  92. 1 def format_name_from_params
  93. 28 if explicit_file_format? then :file
  94. 27 elsif params[:format].present? then params[:format].to_sym
  95. 26 else request.format.to_sym
  96. end
  97. end
  98. 1 def explicit_file_format?
  99. 28 params[:explicit_file] || !Card::Format.registered.member?(request.format)
  100. end
  101. 1 def interpret_mark mark
  102. 23 case mark
  103. when "*previous"
  104. # Why support this? It's only needed in Success, right? Deprecate?
  105. 1 return hard_redirect(Card::Env.previous_location)
  106. when nil
  107. 5 implicit_mark
  108. else
  109. 17 explicit_mark mark
  110. end
  111. end
  112. 1 def explicit_mark mark
  113. # we should find the place where we produce these bad urls
  114. 17 mark.valid_encoding? ? mark : mark.force_encoding("ISO-8859-1").encode("UTF-8")
  115. end
  116. 1 def implicit_mark
  117. case
  118. 5 when initial_setup then ""
  119. 2 when (name = params.dig :card, :name) then name
  120. 3 when view_does_not_require_name? then ""
  121. else home_mark
  122. end
  123. end
  124. 1 def home_mark
  125. Card::Rule.global_setting(:home) || "Home"
  126. end
  127. 1 def view_does_not_require_name?
  128. 3 return false unless (view = params[:view]&.to_sym)
  129. 3 Card::Set::Format::AbstractFormat::ViewOpts.unknown_ok[view]
  130. end
  131. # alters params
  132. 1 def initial_setup
  133. 5 return unless initial_setup?
  134. prepare_setup_card!
  135. end
  136. 1 def initial_setup?
  137. 5 Card::Auth.needs_setup? && Card::Env.html?
  138. end
  139. 1 def prepare_setup_card!
  140. params[:card] = { type_id: Card.default_accounted_type_id }
  141. params[:view] = "setup"
  142. end
  143. end
  144. end

decko/rails/controllers/application_controller.rb

100.0% lines covered

1 relevant lines. 1 lines covered and 0 lines missed.
    
  1. 1 class ApplicationController < ActionController::Base
  2. end

decko/rails/controllers/card_controller.rb

98.72% lines covered

78 relevant lines. 77 lines covered and 1 lines missed.
    
  1. # -*- encoding : utf-8 -*-
  2. # Decko's only controller.
  3. 1 class CardController < ApplicationController
  4. 1 include ::Card::Env::Location
  5. 1 include ::Recaptcha::Verify
  6. 1 include ::Decko::Response
  7. 1 layout nil
  8. 1 attr_reader :card
  9. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  10. # PUBLIC METHODS
  11. 1 def create
  12. 22 handle { card.save! }
  13. end
  14. 1 def read
  15. 21 show
  16. end
  17. 1 def update
  18. 8 card.new_card? ? create : handle { card.update! params[:card] }
  19. end
  20. 1 def delete
  21. 4 handle { card.delete! }
  22. end
  23. # @deprecated
  24. 1 def asset
  25. 2 Rails.logger.info "Routing assets through Card. Recommend symlink from " \
  26. 'Deck to Card gem using "rake decko:update_assets_symlink"'
  27. 2 send_deprecated_asset
  28. end
  29. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  30. # PRIVATE METHODS
  31. 1 private
  32. #-------( FILTERS )
  33. 1 before_action :setup, except: [:asset]
  34. 1 before_action :authenticate, except: [:asset]
  35. 1 before_action :load_mark, only: [:read]
  36. 1 before_action :load_card, except: [:asset]
  37. 1 before_action :load_action, only: [:read]
  38. 1 before_action :refresh_card, only: [:create, :update, :delete]
  39. 1 def setup
  40. 39 Card::Machine.refresh_script_and_style unless params[:explicit_file]
  41. 39 Card::Cache.renew
  42. 39 Card::Env.reset controller: self
  43. end
  44. 1 def authenticate
  45. 39 Card::Auth.signin_with token: params[:token], api_key: params[:api_key]
  46. end
  47. 1 def load_mark
  48. 23 params[:mark] = interpret_mark params[:mark]
  49. end
  50. 1 def load_card
  51. 38 @card = Card.controller_fetch params
  52. 38 raise Card::Error::NotFound unless card
  53. 37 record_as_main
  54. end
  55. 1 def load_action
  56. 28 card.select_action_by_params params
  57. 28 card.content = card.last_draft_content if params[:edit_draft] && card.drafts.present?
  58. end
  59. # TODO: refactor this away this when new layout handling is ready
  60. 1 def record_as_main
  61. 37 Card::Env[:main_name] = params[:main] || card&.name || ""
  62. end
  63. 1 def refresh_card
  64. 16 @card = card.refresh
  65. end
  66. # ----------( HELPER METHODS ) -------------
  67. 1 def handle
  68. 16 Card::Env.success card.name
  69. 16 yield ? cud_success : raise(Card::Error::UserError)
  70. end
  71. # successful create, update, or delete act
  72. 1 def cud_success
  73. 13 success = Card::Env.success.in_context card.name
  74. 13 if success.reload?
  75. reload # instruct JSON to reload
  76. else
  77. 13 redirect_cud_success success
  78. end
  79. end
  80. 1 def show view=nil, status=200
  81. 33 card.action = :read
  82. 33 format = load_format
  83. 33 result = render_page format, view
  84. 33 status = format.error_status || status
  85. 33 respond format, result, status
  86. end
  87. 1 def render_page format, view
  88. 33 view ||= view_from_params
  89. 33 card.act do
  90. 33 format.page self, view, Card::Env.slot_opts
  91. end
  92. end
  93. 1 def view_from_params
  94. 28 params[:view] || params[:v]
  95. end
  96. 1 def handle_exception exception
  97. 5 raise exception if debug_exception?(exception)
  98. 5 @card ||= Card.new
  99. 5 error = Card::Error.report exception, card
  100. 5 show error.class.view, error.class.status_code
  101. end
  102. # TODO: move to exception object
  103. 1 def debug_exception? e
  104. 5 !e.is_a?(Card::Error::UserError) &&
  105. !e.is_a?(ActiveRecord::RecordInvalid) &&
  106. Card::Codename[:debugger] &&
  107. Card[:debugger]&.content =~ /on/ # && !Card::Env.ajax?
  108. end
  109. 1 class << self
  110. 1 def rescue_from_class *klasses
  111. 1 klasses.each do |klass|
  112. 10 rescue_from(klass) { |exception| handle_exception exception }
  113. end
  114. end
  115. 1 def rescue_all?
  116. 1 Cardio.config.rescue_all_in_controller
  117. end
  118. end
  119. 1 rescue_from_class(*Card::Error::UserError.user_error_classes)
  120. 1 rescue_from_class StandardError if rescue_all?
  121. end